﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.IO;
using System.Data.SqlClient;
using System.Data.Common;
using System.Collections;
using System.Collections.ObjectModel;
using Portal.Workflow.Model;
using Portal.Workflow.Library;
using Portal.Database.Service;
using Portal.Web.Utility;
using Portal.Core;
using Portal.Utility;
using Portal.Workflow.Utilities;



namespace Portal.Workflow.Bussiness
{
    public class WorkflowBll : IProcessCommand
    {
        public string ServiceId
        {
            get
            {
                return "WorkflowBll";
            }
        }


        public static DataTable ReadingWorkflowDef(
                    string ConnectionString
                )
        {
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                  " select WorkflowDefId, WorkFlowName=WorkFlowName+' ('+TempWorkingVersion+') / Active version ('+Version+')'  from TableWorkflowDef", null);
            return ds.Tables[0];
        }

        public static DataTable ReadingWorkflowDefForWorkflowTaskForUser(
                   string ProcessType,
                   string ConnectionString
               )
        {
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;
            string CommandText = " select WorkflowDefId, WorkFlowName from TableWorkflowDef where 1=1 ";
            CommandText +=
                " and WorkflowDefId in (select WorkflowDefId from TableWorkflowAction where [sent]=0 and ProcessDone=0 and EmployeeLoginName=@LoginName and toRole=@RoleId ";
            if (!string.IsNullOrEmpty(ProcessType))
            {
                CommandText += " and ProcessType='" + ProcessType + "' ";
            }
            CommandText += " ) order by WorkflowDefId";
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
            CommandText, new DatabaseParamCls[] 
            { 
                new DatabaseParamCls("LoginName", WebSessionUtility.GetCurrentLoginUser().LoginName), 
                new DatabaseParamCls("RoleId", WebSessionUtility.GetCurrentLoginUser().RoleId) 
            });

            return ds.Tables[0];
        }

        public static DataTable ReadingWorkflowDefForWorkflowTask(string ConnectionString)
        {
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                  " select WorkflowDefId, WorkFlowName from TableWorkflowDef ", null);
            return ds.Tables[0];
        }

        //public static DataTable ReadingWorkflowTaskHasSent(
        //    string ConnectionString,
        //    string WorkflowDefId,
        //    string ActiveType,
        //    DateTime dFromDate,
        //    DateTime dToDate)
        //{
        //    Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
        //    oWsInParamCls.ConnectionString = ConnectionString;
        //    string Query = "select TableWorkflowHasSent.*, WorkflowDefName=WorkFlowName,WorkFlowName from [TableWorkflowHasSent] " +
        //                   "        join TableWorkflowDef on TableWorkflowDef.WorkflowDefId=frkWorkflowDefId" +
        //                   "     where EntryBy = @EntryBy" +
        //                   "        and SentDate between '" + dFromDate.ToString("MM/dd/yyyy 00:00") + "' and '" + dToDate.ToString("MM/dd/yyyy 23:59") + "'";
        //    if (!String.IsNullOrEmpty(WorkflowDefId))
        //    {
        //        Query += " and frkWorkflowDefId='" + WorkflowDefId + "'";
        //    }
        //    if (ActiveType.Equals("processed"))
        //    {
        //        Query += " and IsProcessed=1";
        //    }
        //    if (ActiveType.Equals("not-process"))
        //    {
        //        Query += " and IsProcessed=0";
        //    }
        //    Query += " order by [SentDate]";

        //    DataTable dtResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(Query, new DatabaseParamCls[] { new DatabaseParamCls("EntryBy", WebSessionUtility.GetCurrentLoginUser().LoginName) });
        //    return dtResult;
        //}

        //public static DataTable ReadingWorkflowTaskHasSent(
        //   string ConnectionString,
        //   DateTime dFromDate,
        //   DateTime dToDate)
        //{
        //    Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
        //    oWsInParamCls.ConnectionString = ConnectionString;
        //    string Query = "select TableWorkflowHasSent.*, WorkflowDefName=WorkFlowName,WorkFlowName from [TableWorkflowHasSent] " +
        //                   "        join TableWorkflowDef on TableWorkflowDef.WorkflowDefId=frkWorkflowDefId" +
        //                   "     where EntryBy = @EntryBy";
        //    if (dFromDate != new System.DateTime())
        //    {
        //        Query +=
        //                   "        and SentDate between '" + dFromDate.ToString("MM/dd/yyyy 00:00") + "' and '" + dToDate.ToString("MM/dd/yyyy 23:59") + "'";
        //    }
        //    //if (!String.IsNullOrEmpty(WorkflowDefId))
        //    //{
        //    //    Query += " and frkWorkflowDefId='" + WorkflowDefId + "'";
        //    //}
        //    //if (ActiveType.Equals("processed"))
        //    //{
        //    //    Query += " and IsProcessed=1";
        //    //}
        //    //if (ActiveType.Equals("not-process"))
        //    //{
        //    //    Query += " and IsProcessed=0";
        //    //}
        //    Query += " order by [SentDate]";

        //    DataTable dtResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(Query, new DatabaseParamCls[] { new DatabaseParamCls("EntryBy", WebSessionUtility.GetCurrentLoginUser().LoginName) });
        //    return dtResult;
        //}

        //public static DataTable ReadingWorkflowTaskHasReceived(
        //    string ConnectionString,
        //    string WorkflowDefId,
        //    string ActiveType,
        //    DateTime dFromDate,
        //    DateTime dtToDate)
        //{
        //    Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
        //    oWsInParamCls.ConnectionString = ConnectionString;
        //    string Query = "select TableWorkflowHasReceived.*, WorkflowDefName=WorkFlowName,WorkFlowName from [TableWorkflowHasReceived] " +
        //                   "        join TableWorkflowDef on TableWorkflowDef.WorkflowDefId=frkWorkflowDefId" +
        //                   "     where Owner = @Owner " +
        //                   "        and ReceivedDate between '" + dFromDate.ToString("MM/dd/yyyy 00:00") + "' and '" + dtToDate.ToString("MM/dd/yyyy 23:59") + "'";
        //    if (!String.IsNullOrEmpty(WorkflowDefId))
        //    {
        //        Query += " and frkWorkflowDefId='" + WorkflowDefId + "'";
        //    }
        //    if (ActiveType.Equals("processed"))
        //    {
        //        Query += " and HasProcessed=1";
        //    }
        //    if (ActiveType.Equals("not-process"))
        //    {
        //        Query += " and HasProcessed=0";
        //    }
        //    Query += " order by [ReceivedDate]";

        //    DataTable dtResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(Query, new DatabaseParamCls[] { new DatabaseParamCls("Owner", WebSessionUtility.GetCurrentLoginUser().LoginName) });
        //    return dtResult;
        //}


        //public static DataTable ReadingWorkflowTaskHasReceived(
        //    string ConnectionString,
        //    DateTime dFromDate,
        //    DateTime dtToDate)
        //{
        //    Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
        //    oWsInParamCls.ConnectionString = ConnectionString;
        //    string Query = "select TableWorkflowHasReceived.*, WorkflowDefName=WorkFlowName,WorkFlowName from [TableWorkflowHasReceived] " +
        //                   "        join TableWorkflowDef on TableWorkflowDef.WorkflowDefId=frkWorkflowDefId" +
        //                   "     where Owner = @Owner ";
        //    if (dFromDate != new System.DateTime())
        //    {
        //        Query +=
        //                  "        and ReceivedDate between '" + dFromDate.ToString("MM/dd/yyyy 00:00") + "' and '" + dtToDate.ToString("MM/dd/yyyy 23:59") + "'";
        //    }
        //    //if (!String.IsNullOrEmpty(WorkflowDefId))
        //    //{
        //    //    Query += " and frkWorkflowDefId='" + WorkflowDefId + "'";
        //    //}
        //    //if (ActiveType.Equals("processed"))
        //    //{
        //    //    Query += " and HasProcessed=1";
        //    //}
        //    //if (ActiveType.Equals("not-process"))
        //    //{
        //    //    Query += " and HasProcessed=0";
        //    //}
        //    Query += " order by [ReceivedDate]";

        //    DataTable dtResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(Query, new DatabaseParamCls[] { new DatabaseParamCls("Owner", WebSessionUtility.GetCurrentLoginUser().LoginName) });
        //    return dtResult;
        //}

        public static DataTable ReadingWorkflowDefWithXmlData(
                   string ConnectionString
               )
        {
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                  " select WorkflowDefId, XmlData from TableWorkflowDef", null);
            return ds.Tables[0];
        }

        static void ReadingWorkflowList(
              Model.WsInParamCls oWsInParamCls,
              ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                  " select WorkflowDefId, WorkFlowName=WorkFlowName+' ('+TempWorkingVersion+') / Active version ('+Version+')'  from TableWorkflowDef", null);
            oWsReturnParamCls.dsResult = ds;
        }



        public bool CheckExitsWorkflow(
           Model.WsInParamCls oWsInParamCls,
           string WorkflowDefId)
        {
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet("select WorkflowDefId from TableWorkflowDef where WorkflowDefId='" + WorkflowDefId + "'");
            return ds.Tables[0].Rows.Count > 0;
        }



        public void SaveWorkflow(
          Model.WsInParamCls oWsInParamCls,
          ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string WorkflowDefId = oWsInParamCls.KeyId;
            string XmlData = oWsInParamCls.Xml;
            string XmlDataLayout = oWsInParamCls.Keyword;
            string SaveOption = oWsInParamCls.UserId;
            if (string.IsNullOrEmpty(SaveOption)) SaveOption = "0";

            DataSet ds = new DataSet();
            ds.ReadXml(new StringReader(XmlData));
            string WorkFlowDefId = (string)ds.Tables["WorkFlowDef"].Rows[0]["WorkFlowDefId"];
            string WorkFlowName = (string)ds.Tables["WorkFlowDef"].Rows[0]["WorkFlowName"];
            DateTime ReleasedDate = new System.DateTime();
            try
            {
                ReleasedDate = DateTime.Parse(ds.Tables["WorkFlowDef"].Rows[0]["ReleasedDate"].ToString());
            }
            catch { ReleasedDate = System.DateTime.Now; }
            string Version = (string)ds.Tables["WorkFlowDef"].Rows[0]["Version"];
            if (CheckExitsWorkflow(oWsInParamCls, WorkflowDefId))
            {
                string Query =
                    " Delete from TableWorkflowDefVersion where frkWorkflowDefId='" + WorkflowDefId + "' and Version='" + Version + "';" +
                    " Insert into TableWorkflowDefVersion(WorkflowDefVersionId, Version, XmlData, XmlDataLayout, frkWorkflowDefId) values (newid(), @Version, @XmlData, @XmlDataLayout, @WorkFlowDefId);" +
                    " Update TableWorkflowDef set WorkFlowName=@WorkFlowName, TempWorkingVersion=@Version where WorkflowDefId=@WorkflowDefId; " +
                    " Update TableWorkflowDef set XmlData=@XmlData,XmlDataLayout=@XmlDataLayout where WorkflowDefId=@WorkflowDefId and Version=@Version; ";

                if (SaveOption.Equals("1"))
                {
                    Query += " Update TableRunningWorkflowTask set XmlWorkflowData=@XmlWorkflowData where WorkflowDefId=@WorkFlowDefId ";
                }
                DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(Query, new Model.DatabaseParamCls[]{
                     new Model.DatabaseParamCls("WorkFlowDefId",WorkFlowDefId),
                     new Model.DatabaseParamCls("Version",Version),
                     new Model.DatabaseParamCls("XmlData",XmlData),
                     new Model.DatabaseParamCls("XmlDataLayout",XmlDataLayout),
                     new Model.DatabaseParamCls("WorkFlowName",WorkFlowName),
                     new Model.DatabaseParamCls("XmlWorkflowData",XmlData),
                 });
            }
            else
            {
                string Query = " Insert into TableWorkflowDef(WorkflowDefId, WorkFlowName, Version, ReleasedDate, XmlData, XmlDataLayout,TempWorkingVersion) values (@WorkflowDefId, @WorkFlowName, @Version, @ReleasedDate, @XmlData, @XmlDataLayout,@TempWorkingVersion);" +
                               " Insert into TableWorkflowDefVersion(WorkflowDefVersionId, Version, XmlData, XmlDataLayout, frkWorkflowDefId) values (newid(), @Version, @XmlData, @XmlDataLayout, @WorkFlowDefId);";
                if (SaveOption.Equals("1"))
                {
                    Query += " Update TableRunningWorkflowTask set XmlWorkflowData=@XmlWorkflowData where WorkflowDefId=@WorkFlowDefId ";
                }
                DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(Query, new Model.DatabaseParamCls[]{
                     new Model.DatabaseParamCls("WorkFlowDefId",WorkFlowDefId),
                     new Model.DatabaseParamCls("WorkFlowName",WorkFlowName),
                     new Model.DatabaseParamCls("ReleasedDate",DbType.DateTime, ReleasedDate),
                     new Model.DatabaseParamCls("Version",Version),
                     new Model.DatabaseParamCls("XmlData",XmlData),
                     new Model.DatabaseParamCls("XmlDataLayout",XmlDataLayout),
                     new Model.DatabaseParamCls("TempWorkingVersion",Version),
                     new Model.DatabaseParamCls("XmlWorkflowData",XmlData),
                 });
            }
        }



        static void GetWorkflowData(
               Model.WsInParamCls oWsInParamCls,
               ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string WorkflowDefId = oWsInParamCls.KeyId;
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                " select TableWorkflowDefVersion.* from TableWorkflowDefVersion" +
                "   join TableWorkflowDef on TableWorkflowDef.WorkflowDefId = frkWorkflowDefId" +
                " where TempWorkingVersion=TableWorkflowDefVersion.Version" +
                "   and WorkflowDefId='" + WorkflowDefId + "' order by Version DESC", null);
            oWsReturnParamCls.dsResult = ds;
        }

        static void GetAllVersionWorkflowData(
               Model.WsInParamCls oWsInParamCls,
               ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string WorkflowDefId = oWsInParamCls.KeyId;
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                " select TableWorkflowDefVersion.* from TableWorkflowDefVersion" +
                "   join TableWorkflowDef on TableWorkflowDef.WorkflowDefId = frkWorkflowDefId" +
                " where WorkflowDefId='" + WorkflowDefId + "' order by Version DESC", null);
            oWsReturnParamCls.dsResult = ds;
        }

        static void SetActiveVersion(
               Model.WsInParamCls oWsInParamCls,
               ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string WorkflowDefId = oWsInParamCls.KeyId;
            string Version = oWsInParamCls.Keyword;
            DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery
                (
                    " Update TableWorkflowDef set XmlData=" +
                    "       (" +
                    "           select TableWorkflowDefVersion.XmlData from TableWorkflowDefVersion" +
                    "               where TableWorkflowDefVersion.Version='" + Version + "'" +
                        "           and frkWorkflowDefId='" + WorkflowDefId + "'" +
                    "       )" +
                    "  where WorkflowDefId='" + WorkflowDefId + "'" +
                    "  Update TableWorkflowDef set XmlDataLayout=" +
                    "       (" +
                    "           select TableWorkflowDefVersion.XmlDataLayout from TableWorkflowDefVersion" +
                    "               where TableWorkflowDefVersion.Version='" + Version + "'" +
                        "           and frkWorkflowDefId='" + WorkflowDefId + "'" +
                    "       )" +
                    "  where WorkflowDefId='" + WorkflowDefId + "'" +
                    "  Update TableWorkflowDef set Version=" +
                    "       (" +
                    "           select TableWorkflowDefVersion.Version from TableWorkflowDefVersion" +
                    "               where TableWorkflowDefVersion.Version='" + Version + "'" +
                        "           and frkWorkflowDefId='" + WorkflowDefId + "'" +
                    "       )" +
                    "  where WorkflowDefId='" + WorkflowDefId + "'"
                );
        }


        static void GetActiveWorkflowData(
              Model.WsInParamCls oWsInParamCls,
              ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string WorkflowDefId = oWsInParamCls.KeyId;
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                " select XmlData from TableWorkflowDef" +
                "    where WorkflowDefId='" + WorkflowDefId + "'", null);
            oWsReturnParamCls.XmlResult = ds.Tables[0].Rows[0]["XmlData"].ToString();
        }


        static void GetXmlWorkflowDataByWorkflowAction(
               Model.WsInParamCls oWsInParamCls,
               ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string WorkflowActionId = oWsInParamCls.KeyId;
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                " select XmlWorkflowData from TableWorkFlowAction  "+
                "       join TableRunningWorkflowTask on TableRunningWorkflowTask.RunningWorkflowTaskId=TableWorkFlowAction.RunningWorkflowTaskId"+
                " where Id='" + WorkflowActionId + "'");
            oWsReturnParamCls.XmlResult = (string)ds.Tables[0].Rows[0]["XmlWorkflowData"];
        }

        WorkFlowApp CreateWorkFlowApp(string XmlWorkflowData)
        {
            WorkFlowApp wfa = new WorkFlowApp(XmlWorkflowData);
            return wfa;
        }

        public ProcessCls GetProcess(
            WsInParamCls oWsInParamCls,
            WorkFlowApp wfa,
            string ProcessId)
        {
            for (int iIndex = 0; iIndex < wfa.ArrayListProcess.Count; iIndex++)
            {
                ProcessCls tProcessCls = (ProcessCls)wfa.ArrayListProcess[iIndex];
                if (tProcessCls.ProcessId.Equals(ProcessId))
                {
                    return tProcessCls;
                }
            }
            return null;
        }

        public ProcessCls GetStartPoint(
            WsInParamCls oWsInParamCls,
            WorkFlowApp wfa)
        {
            for (int iIndex = 0; iIndex < wfa.ArrayListProcess.Count; iIndex++)
            {
                ProcessCls tProcessCls = (ProcessCls)wfa.ArrayListProcess[iIndex];
                if (tProcessCls.ProcessType == 0)
                {
                    return tProcessCls;
                }
            }
            return null;
        }


        public class InsertDatabaseReturnCls
        {
            public string WorkflowActionId;
            public string BatchId;
        }

        private InsertDatabaseReturnCls InsertIntoDatabase(
            WsInParamCls oWsInParamCls,
            System.Data.Common.DbTransaction dbTransaction,
            WorkFlowApp wfa,
            RoleCls ActiveRoleCls,
            LinkCls linkCls,
            string RunningWorkflowTaskId,
            string Id,
            string GroupBatchId,
            string BatchId,
            string LinkBatchId,
            string RecordId,
            string ProcessId,
            string ComeFromRole,
            string ComeFromRoleName,
            string ComeFrom,
            string ComeFromName,
            string ComeFromOfficeCode,
            string ReplyEmployeeId,
            string ReplyEmployeeOfficeCode,
            string Subject,
            string RecordNote,
            string PreviewUrl,
            string PreviewTarget,
            string DelayNote,
            string LinkId,
            string XmlData,
            ProcessCls fromProcess,
            ProcessCls toProcess,
            string WorkflowStatus,
            string CurrentOffice,
            EmployeeCls ToEmployee,
            RoleCls ToRole,
            int DeleteBeforeNext,
            string LinkParentId,
            string ProcessType,
            int WaitingTasks,
            int ProcessDays,
            string PriorityId,
            string PriorityText,
            DateTime ExpireDate,
            string LinkType,
            string ReturnLinkId,
            string Owner,
            string ExtraInfo,
            string ExtraData,
            int StartWorkFlowRecord,
            string SendToUsers,
            int IsReply)
        {
            InsertDatabaseReturnCls oInsertDatabaseReturnCls = new InsertDatabaseReturnCls();
            string WorkFlowDefId = wfa.WorkFlowDefCls.WorkFlowDefId;
            string XmlWorkflowData = wfa.WorkFlowDefCls.XmlWorkflowData;

            WorkFlowDefCls oWorkFlowDefCls = wfa.WorkFlowDefCls;
            string Query = "";

            ProcessCls NextProcess = GetProcess(oWsInParamCls, wfa, linkCls.toNodeId);

            EmployeeCls employeeCls = ToEmployee;
            bool AllowInsert = true;

            if (AllowInsert)
            {
                string WorkflowActionId = System.Guid.NewGuid().ToString();
                if (Id != null)
                {
                    WorkflowActionId = Id;
                }
                oInsertDatabaseReturnCls.WorkflowActionId = WorkflowActionId;
                //RoleCls FoundRole = wfa.FindRole(ToEmployee.TempRoleId[0]);

                string CommandText = "Insert into TableWorkFlowAction(RunningWorkflowTaskId, WorkflowDefId, WorkflowDefName, GroupBatchId, BatchId,LinkBatchId, Id, EmployeeId, EmployeeLoginName, RecordId,Subject,RecordNote,ActionDate,ProcessId,ViewParam,ComeFrom,ComeFromName,PreviewUrl,DelayNote,LinkId,fromRole,fromRoleName, toRole,toRoleName, fromProcessId,fromProcessName,toProcessId,toProcessName,WorkflowStatus,fromOfficeCode,toOfficeCode,XmlData,LinkParentId, Sent, ProcessType, ProcessDone,WaitingTasks, ProcessDays, PriorityId, PriorityText, ExpireDate, LinkType, ReturnLinkId, [Owner], ExtraInfo, ExtraData, StartWorkFlowRecord, SendToUsers, PreviewTarget, IsReply) values (@RunningWorkflowTaskId, @WorkflowDefId, @WorkflowDefName, @GroupBatchId, @BatchId, @LinkBatchId, @WorkflowActionId, @EmployeeId,@EmployeeLoginName, @RecordId,@Subject,@RecordNote,GetDate(),@ProcessId,@ViewParam,@ComeFrom,@ComeFromName,@PreviewUrl,@DelayNote,@LinkId,@fromRole,@fromRoleName,@toRole,@toRoleName,@fromProcessId,@fromProcessName,@toProcessId,@toProcessName,@WorkflowStatus,@fromOfficeCode,@toOfficeCode,@XmlData,@LinkParentId, @Sent, @ProcessType, 0,@WaitingTasks,@ProcessDays, @PriorityId, @PriorityText,@ExpireDate, @LinkType, @ReturnLinkId,@Owner,@ExtraInfo, @ExtraData, @StartWorkFlowRecord, @SendToUsers, @PreviewTarget, @IsReply)";
                DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                    dbTransaction,
                    CommandText,
                    new Model.DatabaseParamCls[]{
                        new Model.DatabaseParamCls("RunningWorkflowTaskId",RunningWorkflowTaskId),
                        new Model.DatabaseParamCls("GroupBatchId",GroupBatchId),
                        new Model.DatabaseParamCls("BatchId",BatchId),
                        new Model.DatabaseParamCls("LinkBatchId",LinkBatchId),
                        new Model.DatabaseParamCls("WorkflowActionId",WorkflowActionId),
                        new Model.DatabaseParamCls("WorkFlowDefId",WorkFlowDefId),
                        new Model.DatabaseParamCls("WorkflowDefName",oWorkFlowDefCls.WorkFlowName),
                        new Model.DatabaseParamCls("EmployeeId",employeeCls.EmployeeId),
                        new Model.DatabaseParamCls("EmployeeLoginName",employeeCls.LoginName),
                        new Model.DatabaseParamCls("RecordId",RecordId),
                        new Model.DatabaseParamCls("ProcessId",ProcessId),
                        new Model.DatabaseParamCls("RecordNote",RecordNote),
                        new Model.DatabaseParamCls("Subject",Subject),
                        new Model.DatabaseParamCls("ViewParam",linkCls.NextViewParam),
                        new Model.DatabaseParamCls("ComeFrom",ComeFrom),
                        new Model.DatabaseParamCls("ComeFromName",ComeFromName),
                        new Model.DatabaseParamCls("PreviewUrl",PreviewUrl),
                        new Model.DatabaseParamCls("DelayNote",DelayNote),
                        new Model.DatabaseParamCls("LinkId",LinkId),
                        new Model.DatabaseParamCls("LinkParentId",LinkParentId),
                        new Model.DatabaseParamCls("Sent",DbType.Int32, 0),
                        new Model.DatabaseParamCls("ProcessDays",DbType.Int32, ProcessDays),
                        new Model.DatabaseParamCls("WaitingTasks",DbType.Int32, WaitingTasks),
                        new Model.DatabaseParamCls("ProcessType",ProcessType),
                        new Model.DatabaseParamCls("fromRole",ComeFromRole),
                        new Model.DatabaseParamCls("fromRoleName",ComeFromRoleName),
                        new Model.DatabaseParamCls("toRole",ToRole.RoleId),
                        new Model.DatabaseParamCls("toRoleName",ToRole.RoleName),
                        new Model.DatabaseParamCls("fromProcessId",fromProcess.ProcessId),
                        new Model.DatabaseParamCls("fromProcessName",fromProcess.ProcessName),
                        new Model.DatabaseParamCls("toProcessId",toProcess.ProcessId),
                        new Model.DatabaseParamCls("toProcessName",toProcess.ProcessName),
                        new Model.DatabaseParamCls("WorkflowStatus",linkCls.NextViewParam),
                        new Model.DatabaseParamCls("XmlData",XmlData),
                        new Model.DatabaseParamCls("fromOfficeCode",ComeFromOfficeCode),
                        new Model.DatabaseParamCls("toOfficeCode",employeeCls.OfficeCode),
                        new Model.DatabaseParamCls("PriorityId",PriorityId),
                        new Model.DatabaseParamCls("PriorityText",PriorityText),
                        new Model.DatabaseParamCls("ExpireDate",DbType.DateTime, ExpireDate),
                        new Model.DatabaseParamCls("LinkType",LinkType),
                        new Model.DatabaseParamCls("ReturnLinkId",ReturnLinkId),
                        new Model.DatabaseParamCls("Owner",Owner),
                        new Model.DatabaseParamCls("ExtraInfo",ExtraInfo),
                        new Model.DatabaseParamCls("ExtraData",ExtraData),
                        new Model.DatabaseParamCls("SendToUsers",SendToUsers),
                        new Model.DatabaseParamCls("PreviewTarget",PreviewTarget),
                        new Model.DatabaseParamCls("StartWorkFlowRecord",StartWorkFlowRecord),
                        //new Model.DatabaseParamCls("RunningWorkflowTaskId",RunningWorkflowTaskId),
                        //new Model.DatabaseParamCls("frkWorkflowHasSentId",WorkflowHasSentId),
                        new Model.DatabaseParamCls("IsReply",IsReply),
                    });


                ////nhet vao lich su
                //CommandText = "Insert into TableWorkFlowActionHistory(InsertDate,XmlWorkflowData, BatchId,LinkBatchId, WorkflowActionId,WorkFlowDefId,WorkflowDefName,EmployeeId, EmployeeLoginName, RecordId,Subject,RecordNote,ActionDate,ProcessId,ViewParam,ComeFrom,ComeFromName,PreviewUrl,DelayNote,LinkId,fromRole,fromRoleName, toRole,toRoleName, fromProcessId,fromProcessName,toProcessId,toProcessName,WorkflowStatus,fromOfficeCode,toOfficeCode,XmlData,LinkParentId, Sent, ProcessType, ProcessDone,WaitingTasks, ProcessDays, PriorityId, PriorityText, ExpireDate, LinkType, ReturnLinkId, [Owner], ExtraInfo, ExtraData, StartWorkFlowRecord, SendToUsers, PreviewTarget, frkRunningWorkflowTaskId,IsNotify,frkWorkflowHasSentId, IsReply) values (GetDate(), @XmlWorkflowData, @BatchId, @LinkBatchId, @WorkflowActionId, @WorkFlowDefId,@WorkflowDefName,@EmployeeId,@EmployeeLoginName, @RecordId,@Subject,@RecordNote,GetDate(),@ProcessId,@ViewParam,@ComeFrom,@ComeFromName,@PreviewUrl,@DelayNote,@LinkId,@fromRole,@fromRoleName,@toRole,@toRoleName,@fromProcessId,@fromProcessName,@toProcessId,@toProcessName,@WorkflowStatus,@fromOfficeCode,@toOfficeCode,@XmlData,@LinkParentId, @Sent, @ProcessType, 0,@WaitingTasks,@ProcessDays, @PriorityId, @PriorityText,@ExpireDate, @LinkType, @ReturnLinkId,@Owner,@ExtraInfo, @ExtraData, @StartWorkFlowRecord, @SendToUsers, @PreviewTarget,@frkRunningWorkflowTaskId,@IsNotify,@frkWorkflowHasSentId, @IsReply)";
                //DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                //    dbTransaction,
                //    CommandText,
                //    new Model.DatabaseParamCls[]{
                //        new Model.DatabaseParamCls("XmlWorkflowData",XmlWorkflowData),
                //        new Model.DatabaseParamCls("BatchId",BatchId),
                //        new Model.DatabaseParamCls("LinkBatchId",LinkBatchId),
                //        new Model.DatabaseParamCls("WorkflowActionId",WorkflowActionId),
                //        new Model.DatabaseParamCls("WorkFlowDefId",WorkFlowDefId),
                //        new Model.DatabaseParamCls("WorkflowDefName",oWorkFlowDefCls.WorkFlowName),
                //        new Model.DatabaseParamCls("EmployeeId",employeeCls.EmployeeId),
                //        new Model.DatabaseParamCls("EmployeeLoginName",employeeCls.LoginName),
                //        new Model.DatabaseParamCls("RecordId",RecordId),
                //        new Model.DatabaseParamCls("ProcessId",ProcessId),
                //        new Model.DatabaseParamCls("RecordNote",RecordNote),
                //        new Model.DatabaseParamCls("Subject",Subject),
                //        new Model.DatabaseParamCls("ViewParam",linkCls.NextViewParam),
                //        new Model.DatabaseParamCls("ComeFrom",ComeFrom),
                //        new Model.DatabaseParamCls("ComeFromName",ComeFromName),
                //        new Model.DatabaseParamCls("PreviewUrl",PreviewUrl),
                //        new Model.DatabaseParamCls("DelayNote",DelayNote),
                //        new Model.DatabaseParamCls("LinkId",LinkId),
                //        new Model.DatabaseParamCls("LinkParentId",LinkParentId),
                //        new Model.DatabaseParamCls("Sent",DbType.Int32, 0),
                //        new Model.DatabaseParamCls("ProcessDays",DbType.Int32, ProcessDays),
                //        new Model.DatabaseParamCls("WaitingTasks",DbType.Int32, WaitingTasks),
                //        new Model.DatabaseParamCls("ProcessType",ProcessType),
                //        new Model.DatabaseParamCls("fromRole",ComeFromRole),
                //        new Model.DatabaseParamCls("fromRoleName",ComeFromRoleName),
                //        new Model.DatabaseParamCls("toRole",ToRole.RoleId),
                //        new Model.DatabaseParamCls("toRoleName",ToRole.RoleName),
                //        new Model.DatabaseParamCls("fromProcessId",fromProcess.ProcessId),
                //        new Model.DatabaseParamCls("fromProcessName",fromProcess.ProcessName),
                //        new Model.DatabaseParamCls("toProcessId",toProcess.ProcessId),
                //        new Model.DatabaseParamCls("toProcessName",toProcess.ProcessName),
                //        new Model.DatabaseParamCls("WorkflowStatus",linkCls.NextViewParam),
                //        new Model.DatabaseParamCls("XmlData",XmlData),
                //        new Model.DatabaseParamCls("fromOfficeCode",ComeFromOfficeCode),
                //        new Model.DatabaseParamCls("toOfficeCode",employeeCls.OfficeCode),
                //        new Model.DatabaseParamCls("PriorityId",PriorityId),
                //        new Model.DatabaseParamCls("PriorityText",PriorityText),
                //        new Model.DatabaseParamCls("ExpireDate",DbType.DateTime, ExpireDate),
                //        new Model.DatabaseParamCls("LinkType",LinkType),
                //        new Model.DatabaseParamCls("ReturnLinkId",ReturnLinkId),
                //        new Model.DatabaseParamCls("Owner",Owner),
                //        new Model.DatabaseParamCls("ExtraInfo",ExtraInfo),
                //        new Model.DatabaseParamCls("ExtraData",ExtraData),
                //        new Model.DatabaseParamCls("SendToUsers",SendToUsers),
                //        new Model.DatabaseParamCls("PreviewTarget",PreviewTarget),
                //        new Model.DatabaseParamCls("StartWorkFlowRecord",StartWorkFlowRecord),
                //        new Model.DatabaseParamCls("frkRunningWorkflowTaskId",RunningWorkflowTaskId),
                //        new Model.DatabaseParamCls("IsNotify",0),
                //        new Model.DatabaseParamCls("frkWorkflowHasSentId",WorkflowHasSentId),
                //        new Model.DatabaseParamCls("IsReply",IsReply),
                //    });
            }
            if (LinkParentId != null)
            {
                string CommandText = "Update TableWorkflowAction set Sent=1 where Id=@LinkParentId";
                DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                  dbTransaction,
                  CommandText,
                  new Model.DatabaseParamCls[]{
                         new Model.DatabaseParamCls("LinkParentId",LinkParentId)
                    });
            }

            //doan nay update target action
            //sqlCommand.Parameters.Clear();
            Query = linkCls.targetAction.Trim();
            if (Query.Trim().Length > 0)
            {
                Query = Query.Replace("@RecordId", "'" + RecordId + "'");
                Query = Query.Replace("@BatchId", "'" + BatchId + "'");
                DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                  dbTransaction,
                  Query);

                //sqlCommand.CommandText = Query;
                //sqlCommand.ExecuteNonQuery();
            }

            oInsertDatabaseReturnCls.BatchId = BatchId;
            return oInsertDatabaseReturnCls;
        }


        public static WsInParamCls CreateWsInParamCls(string SiteId)
        {
            SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);
            WsInParamCls oWsInParamCls = new WsInParamCls();
            oWsInParamCls.ConnectionString = oSiteParam.ConnectionString;
            if (WebSessionUtility.GetCurrentLoginUser() != null)
            {
                oWsInParamCls.LoginName = WebSessionUtility.GetCurrentLoginUser().LoginName;
            }
            oWsInParamCls.PathRoot = oSiteParam.PathRoot;
            oWsInParamCls.HttpRoot = oSiteParam.HttpRoot;
            oWsInParamCls.SiteId = oSiteParam.SiteId;
            oWsInParamCls.RoleId = WebSessionUtility.GetCurrentLoginUser().RoleId;

            return oWsInParamCls;
        }

        public void StartWorkflow(
            string SiteId,
            DbTransaction dbTransaction,
            StartWorkflowParamCls oStartWorkflowParamCls)
        {
            SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);
            Model.WsInParamCls
                    oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.SiteId = SiteId;
            oWsInParamCls.ConnectionString = oSiteParam.ConnectionString;
            oWsInParamCls.Xml =
                WorkFlowAppCommandText.GetStartWorkflowCommandText(oStartWorkflowParamCls);
            oWsInParamCls.KeyId = oStartWorkflowParamCls.WorkflowDefId;
            Model.WsReturnParamCls oWsReturnParamCls = new Model.WsReturnParamCls();
            StartWorkFlow(dbTransaction, oWsInParamCls, ref oWsReturnParamCls);
        }

        public string StartWorkFlow(
            WsInParamCls oWsInParamCls,
            System.Data.Common.DbTransaction dbTransaction,
            string XmlWorkflowData,
            string Id,
            string GroupBatchId,
            string BatchId,
            string ComeFrom,
            string ComeFromName,
            string ComeFromOfficeCode,
            string ComeFromRoleId,
            string RecordId,
            string Subject,
            string RecordNote,
            string XmlData,
            string PreviewUrl,
            string PreviewTarget,
            int DeleteBeforeNext,
            string PriorityId,
            string PriorityText,
            DateTime ExpireDate,
            string LinkType,
            string ReturnLinkId,
            string Owner,
            string ExtraInfo,
            string ExtraData,
            string SendToUsers)
        {
            WorkFlowApp wfa = CreateWorkFlowApp(XmlWorkflowData);
            ProcessCls StartPointProcess = GetStartPoint(oWsInParamCls, wfa);
            if (StartPointProcess == null) throw new Exception("Start point not found!");

            return StartWorkFlowWithProcess(oWsInParamCls, dbTransaction, wfa, Id, StartPointProcess.ProcessId, GroupBatchId, BatchId, ComeFrom, ComeFromName, ComeFromOfficeCode, ComeFromRoleId, RecordId, Subject, RecordNote, PreviewUrl, PreviewTarget, DeleteBeforeNext, PriorityId, PriorityText, ExpireDate, LinkType, ReturnLinkId, Owner, ExtraInfo, ExtraData, SendToUsers);
        }

        public void StartWorkFlow(Model.WsInParamCls oWsInParamCls, ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            StartWorkFlow(null, oWsInParamCls, ref oWsReturnParamCls);
        }

        public void StartWorkFlow(
            DbTransaction dbTransaction,
            Model.WsInParamCls oWsInParamCls,
            ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string WorkflowDefId = oWsInParamCls.KeyId;

            DataSet ds = new DataSet();
            ds.ReadXml(new StringReader(oWsInParamCls.Xml));

            string XmlWorkflowData = null;
            try
            {
                XmlWorkflowData = ds.Tables[0].Rows[0]["XmlWorkflowData"].ToString();
            }
            catch { }

            string Id = null;
            try
            {
                Id = ds.Tables[0].Rows[0]["Id"].ToString();
            }
            catch { }

            string LinkType = "Sequence";
            string ReturnLinkId = "";
            string BatchId = "";
            try
            {
                BatchId = ds.Tables[0].Rows[0]["BatchId"].ToString();
            }
            catch { }
            string GroupBatchId = BatchId;
            try
            {
                GroupBatchId = ds.Tables[0].Rows[0]["GroupBatchId"].ToString();
            }
            catch { GroupBatchId = BatchId; }
            string ComeFrom = "";
            try
            {
                ComeFrom = ds.Tables[0].Rows[0]["ComeFrom"].ToString();
            }
            catch { }
            string ComeFromName = "";
            try
            {
                ComeFromName = ds.Tables[0].Rows[0]["ComeFromName"].ToString();
            }
            catch { }
            string ComeFromOfficeCode = "";
            try
            {
                ComeFromOfficeCode = ds.Tables[0].Rows[0]["ComeFromOfficeCode"].ToString();
            }
            catch { }

            string ComeFromRoleId = "";
            try
            {
                ComeFromRoleId = ds.Tables[0].Rows[0]["ComeFromRoleId"].ToString();
            }
            catch { }

            string RecordId = "";
            try
            {
                RecordId = ds.Tables[0].Rows[0]["RecordId"].ToString();
            }
            catch { }
            string Subject = "";
            try
            {
                Subject = ds.Tables[0].Rows[0]["Subject"].ToString();
            }
            catch { }
            string RecordNote = "";
            try
            {
                RecordNote = ds.Tables[0].Rows[0]["RecordNote"].ToString();
            }
            catch { }
            string XmlData = "";
            try
            {
                XmlData = ds.Tables[0].Rows[0]["XmlData"].ToString();
            }
            catch { }
            string PreviewUrl = "";
            try
            {
                PreviewUrl = ds.Tables[0].Rows[0]["PreviewUrl"].ToString();
            }
            catch { }

            string PreviewTarget = "_self";
            try
            {
                PreviewTarget = ds.Tables[0].Rows[0]["PreviewTarget"].ToString();
            }
            catch { }


            int DeleteBeforeNext = 0;
            try
            {
                DeleteBeforeNext = int.Parse(ds.Tables[0].Rows[0]["DeleteBeforeNext"].ToString());
            }
            catch { }
            string PriorityId = "";
            try
            {
                PriorityId = ds.Tables[0].Rows[0]["PriorityId"].ToString();
            }
            catch { }
            string PriorityText = "";
            try
            {
                PriorityText = ds.Tables[0].Rows[0]["PriorityText"].ToString();
            }
            catch { }
            string Owner = "";
            try
            {
                Owner = ds.Tables[0].Rows[0]["Owner"].ToString();
            }
            catch { }

            string ExtraInfo = "";
            try
            {
                ExtraInfo = ds.Tables[0].Rows[0]["ExtraInfo"].ToString();
            }
            catch { }

            string ExtraData = "";
            try
            {
                ExtraData = ds.Tables[0].Rows[0]["ExtraData"].ToString();
            }
            catch { }


            string SendToUsers = "";
            try
            {
                SendToUsers = ds.Tables[0].Rows[0]["SendToUsers"].ToString();
            }
            catch { }

            DateTime ExpireDate = new System.DateTime();
            try
            {
                ExpireDate = DateTime.Parse(ds.Tables[0].Rows[0]["ExpireDate"].ToString());
            }
            catch { ExpireDate = System.DateTime.Now.AddDays(2); }

            StartWorkFlow(
                oWsInParamCls,
                dbTransaction,
                XmlWorkflowData,
                Id,
                GroupBatchId,
                BatchId,
                ComeFrom,
                ComeFromName,
                ComeFromOfficeCode,
                ComeFromRoleId,
                RecordId,
                Subject,
                RecordNote,
                PreviewUrl,
                PreviewTarget,
                DeleteBeforeNext,
                PriorityId,
                PriorityText,
                ExpireDate,
                LinkType,
                ReturnLinkId,
                Owner,
                ExtraInfo,
                ExtraData,
                SendToUsers);
        }

        public LinkCls GetLinkFromStartPoint(
            WsInParamCls oWsInParamCls,
            WorkFlowApp wfa,
            string ComeFromRoleId,
            ProcessCls StartPointProcess)
        {
            for (int iIndex = 0; iIndex < wfa.ArrayLinks.Count; iIndex++)
            {
                LinkCls linkCls = (LinkCls)wfa.ArrayLinks[iIndex];
                string[] RoleIds = linkCls.RoleAllowStartFromFirstProcessId.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                if (linkCls.fromNodeId.Equals(StartPointProcess.ProcessId))
                {
                    for (int iCheck = 0; iCheck < RoleIds.Length; iCheck++)
                    {
                        if (RoleIds[iCheck].Trim().ToLower().Equals(ComeFromRoleId.Trim().ToLower()))
                        {
                            return linkCls;
                        }
                    }
                }
            }

            //neu khong tim thay role nao thi start cai bat ky bat dau thoi...!
            for (int iIndex = 0; iIndex < wfa.ArrayLinks.Count; iIndex++)
            {
                LinkCls linkCls = (LinkCls)wfa.ArrayLinks[iIndex];
                if (linkCls.fromNodeId.Equals(StartPointProcess.ProcessId))
                {
                    return linkCls;
                }
            }
            return null;
        }


        public RoleCls GetRole(
            WsInParamCls oWsInParamCls,
            WorkFlowApp wfa,
            string RoleId)
        {
            for (int iIndex = 0; iIndex < wfa.ArrayRoles.Count; iIndex++)
            {
                RoleCls tRoleCls = (RoleCls)wfa.ArrayRoles[iIndex];
                if (tRoleCls.RoleId.Equals(RoleId))
                {
                    return tRoleCls;
                }
            }
            return null;
        }

        public string CutText(string Subject, int MaxWord)
        {
            Subject = System.Web.HttpUtility.HtmlDecode(Subject);
            string[] AllText = Subject.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            string rSubject = "";
            for (int iIndex = 0; iIndex < AllText.Length; iIndex++)
            {
                rSubject = rSubject + AllText[iIndex];
                if (iIndex < MaxWord)
                {
                    rSubject = rSubject + " ";
                }
                else
                {
                    rSubject = rSubject + "...";
                    break;
                }
            }
            return rSubject.Trim();
        }

        public static EmployeeCls CreateEmployeeModelFromUser(string SiteId, string EmployeeId)
        {
            SiteParam OSiteParam = WebEnvironments.CreateSiteParam(SiteId);
            Portal.Systems.Model.UserCls OUser = SystemBussinessUtility.CreateSystemsBussinessProcess(SiteId).CreateUserModel(SiteId, EmployeeId);
            EmployeeCls OEmployee = new EmployeeCls();
            OEmployee.EmployeeId = OUser.UserId;
            OEmployee.LoginName = OUser.LoginName;
            OEmployee.FullName = OUser.FullName;
            OEmployee.OfficeCode = OSiteParam.SiteCode;
            OEmployee.TempRoleId = new string[] { WebSessionUtility.GetCurrentLoginUser().RoleId };
            OEmployee.ToRole = new RoleCls();
            OEmployee.ToRole.RoleId = WebSessionUtility.GetCurrentLoginUser().RoleId;
            OEmployee.ToRole.RoleName = WebSessionUtility.GetCurrentLoginUser().RoleName;
            //Systems.Model.RoleCls[] Roles = SystemBussinessUtility.CreateSystemsBussinessProcess(SiteId).ReadingRolesForUser(SiteId, OUser.UserId);
            //OEmployee.TempRoleId = new string[Roles.Length];
            //for (int iIndex = 0; iIndex < Roles.Length; iIndex++)
            //{
            //    OEmployee.TempRoleId[iIndex] = Roles[iIndex].RoleId;
            //}

            return OEmployee;
        }

        public string StartWorkFlowWithProcess(
            WsInParamCls oWsInParamCls,
            System.Data.Common.DbTransaction dbTransaction,
            WorkFlowApp wfa,
            string Id,
            string ProcessId,
            string GroupBatchId,
            string BatchId,
            string ComeFrom,
            string ComeFromName,
            string ComeFromOfficeCode,
            string ComeFromRoleId,
            string RecordId,
            string Subject,
            string RecordNote,
            string XmlData,
            string PreviewUrl,
            string PreviewTarget,
            int DeleteBeforeNext,
            string PriorityId,
            string PriorityText,
            DateTime ExpireDate,
            string LinkType,
            string ReturnLinkId,
            string Owner,
            string ExtraInfo,
            string ExtraData,
            string SendToUsers)
        {
            string SiteId = oWsInParamCls.SiteId;
            bool HasTrans = dbTransaction != null;
            if (!HasTrans)
            {
                //SqlConnection sqlConnection = new SqlConnection(ConnectionString);
                //sqlConnection.Open();
                dbTransaction = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).BeginTransaction();// sqlConnection.BeginTransaction();
            }

            //doan nay lay thang role effected
            string WorkflowDefId = wfa.WorkFlowDefCls.WorkFlowDefId;
            string XmlWorkflowData = wfa.WorkFlowDefCls.XmlWorkflowData;
            ProcessCls StartPointProcess = GetProcess(oWsInParamCls, wfa, ProcessId);
            if (StartPointProcess == null) throw new Exception("Không tìm thấy điểm bắt đầu quy trình!");
            if (StartPointProcess.CheckStartType == 1)
            {
                //kiem tra xem co quyen khoi dong workflow khong
                string[] RoleIds = StartPointProcess.RoleForStart.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                bool Found = false;
                for (int iIndex = 0; iIndex < RoleIds.Length; iIndex++)
                {
                    if (RoleIds[iIndex].Trim().Equals(ComeFromRoleId))
                    {
                        Found = true;
                        break;
                    }
                }
                if (!Found) throw new Exception("Không có quyền tạo quy trình!");
            }
            LinkCls linkCls = GetLinkFromStartPoint(oWsInParamCls, wfa, ComeFromRoleId, StartPointProcess);
            if (linkCls == null) throw new Exception("Không tìm thấy link xuất phát từ điểm bắt đầu!");
            ProcessCls NextProcess = GetProcess(oWsInParamCls, wfa, linkCls.toNodeId);
            if (NextProcess == null) throw new Exception("Không tìm thấy điểm xử lý tiếp theo!");
            //if (linkCls.RoleIds == null) throw new Exception("Không tìm thấy role!");
            //if (linkCls.RoleIds.Length == 0) throw new Exception("Invalid roles for start workflow!");
            Systems.Model.RoleCls ORole = SystemBussinessUtility.CreateSystemsBussinessProcess(SiteId).CreateRoleModel(SiteId, ComeFromRoleId);
            if (ORole == null)
            {
                throw new Exception("Không tìm thấy vị trí công việc này trong hệ thống!");
            }

            RoleCls ActiveRoleCls = new RoleCls();  //GetRole(oWsInParamCls, wfa, ComeFromRoleId);
            ActiveRoleCls.RoleId = ORole.RoleId;
            ActiveRoleCls.RoleCode = ORole.RoleCode;
            ActiveRoleCls.RoleName = ORole.RoleName;
            RoleCls ComeFromRoleCls = ActiveRoleCls;
            
            EmployeeCls EmployeeCreated = CreateEmployeeModelFromUser(SiteId, ComeFrom);// (EmployeeCls)ActiveRoleCls.ArrayListEmployees[0];
            if (EmployeeCreated == null) throw new Exception("Không tìm thấy đối tượng [" + ComeFromName + "]");
            EmployeeCreated.TempRoleId = new string[] { ComeFromRoleId };
            //Check xem co nam trong role  nao do khong


            //if (EmployeeCreated == null) throw new Exception("Đối tượng này chưa xác định vị trí công việc! Không khởi tạo được quy trình!");
            if (String.IsNullOrEmpty(EmployeeCreated.TempRoleId[0])) throw new Exception("Đối tượng này chưa xác định vị trí công việc! Không khởi tạo được quy trình!");

            if (string.IsNullOrEmpty(ExtraInfo)) ExtraInfo = "";
            if (string.IsNullOrEmpty(ExtraData)) ExtraData = "";
          
            string LinkId = linkCls.LinkId;
            string LinkBatchId = System.Guid.NewGuid().ToString().Substring(0, 8);
            try
            {
                string RunningWorkflowTaskId = System.Guid.NewGuid().ToString();
                //doan nat nhet vao cho RunningWorkflow
                SqlCommand oSqlCommand = ((SqlTransaction)dbTransaction).Connection.CreateCommand();
                oSqlCommand.Transaction = ((SqlTransaction)dbTransaction);
                oSqlCommand.CommandText = "Insert into TableRunningWorkflowTask(RunningWorkflowTaskId, WorkFlowDefId, WorkflowDefName, Subject, Description, ObjectType, ObjectRecordId, ObjectExtraData, StartDate, StartByLoginName, StartById, StartByFullName, WorkingStatus, ProcessAt, ProcessBy, PreviewUrl, StartByRoleId, StartByRoleName, ProcessViewBt, ComeFromOfficeCode, DaysForProcess, CurrentDate, XmlWorkflowData) values (@RunningWorkflowTaskId, @WorkFlowDefId, @WorkflowDefName, @Subject, @Description, @ObjectType, @ObjectRecordId, @ObjectExtraData, @StartDate, @StartByLoginName, @StartById, @StartByFullName, @WorkingStatus, @ProcessAt, @ProcessBy, @PreviewUrl, @StartByRoleId, @StartByRoleName, @ProcessViewBt, @ComeFromOfficeCode,0, @StartDate, @XmlWorkflowData)";
                oSqlCommand.Parameters.Add("@RunningWorkflowTaskId", SqlDbType.VarChar).Value = RunningWorkflowTaskId;
                oSqlCommand.Parameters.Add("@WorkFlowDefId", SqlDbType.VarChar).Value = WorkflowDefId;
                oSqlCommand.Parameters.Add("@WorkflowDefName", SqlDbType.NVarChar).Value = wfa.WorkFlowDefCls.WorkFlowName;
                oSqlCommand.Parameters.Add("@Subject", SqlDbType.NVarChar).Value = Subject;
                oSqlCommand.Parameters.Add("@Description", SqlDbType.NVarChar).Value = "";
                
                oSqlCommand.Parameters.Add("@ObjectType", SqlDbType.NVarChar).Value = ExtraInfo;
                oSqlCommand.Parameters.Add("@ObjectRecordId", SqlDbType.VarChar).Value = RecordId;
                oSqlCommand.Parameters.Add("@ObjectExtraData", SqlDbType.VarChar).Value = ExtraData;
                oSqlCommand.Parameters.Add("@StartDate", SqlDbType.DateTime).Value = System.DateTime.Now;
                oSqlCommand.Parameters.Add("@StartByLoginName", SqlDbType.VarChar).Value = ComeFrom;
                oSqlCommand.Parameters.Add("@StartById", SqlDbType.VarChar).Value = EmployeeCreated.EmployeeId;
                oSqlCommand.Parameters.Add("@StartByFullName", SqlDbType.NVarChar).Value = ComeFromName;
                oSqlCommand.Parameters.Add("@WorkingStatus", SqlDbType.VarChar).Value = "Start";
                oSqlCommand.Parameters.Add("@ProcessAt", SqlDbType.NVarChar).Value = NextProcess.ProcessName;
                oSqlCommand.Parameters.Add("@ProcessBy", SqlDbType.NVarChar).Value = EmployeeCreated.LoginName;
                oSqlCommand.Parameters.Add("@PreviewUrl", SqlDbType.NVarChar).Value = PreviewUrl;
                oSqlCommand.Parameters.Add("@StartByRoleId", SqlDbType.NVarChar).Value = ComeFromRoleId;
                if (ComeFromRoleCls != null)
                {
                    oSqlCommand.Parameters.Add("@StartByRoleName", SqlDbType.NVarChar).Value = ComeFromRoleCls.RoleName;
                }
                else
                {
                    oSqlCommand.Parameters.Add("@StartByRoleName", SqlDbType.NVarChar).Value = "";
                }
                string ProcessViewBt = "";
                oSqlCommand.Parameters.Add("@ProcessViewBt", SqlDbType.NVarChar).Value = ProcessViewBt;
                oSqlCommand.Parameters.Add("@ComeFromOfficeCode", SqlDbType.NVarChar).Value = ComeFromOfficeCode;
                oSqlCommand.Parameters.Add("@XmlWorkflowData", SqlDbType.NVarChar).Value = XmlWorkflowData;
                oSqlCommand.ExecuteNonQuery();

                ////them vao
                //DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                //  dbTransaction,
                //  " Delete from TableWorkflowCurrentProcess where RecordId=@RecordId; " +
                //  " Insert into TableWorkflowCurrentProcess(RecordId,ObjectType,CurrentProcess,CurrentProcessFullName) values (@RecordId,@ObjectType,@CurrentProcess,@CurrentProcessFullName)",
                //  new Model.DatabaseParamCls[]{
                //                new Model.DatabaseParamCls("RecordId",RecordId),
                //                new Model.DatabaseParamCls("ObjectType",ExtraInfo),
                //                new Model.DatabaseParamCls("CurrentProcess",EmployeeCreated.LoginName),
                //                new Model.DatabaseParamCls("CurrentProcessFullName",EmployeeCreated.FullName),
                //        }, CommandType.Text);

                InsertDatabaseReturnCls oInsertDatabaseReturnCls =
                InsertIntoDatabase(oWsInParamCls, dbTransaction, wfa, ActiveRoleCls, linkCls, RunningWorkflowTaskId, Id, GroupBatchId, BatchId, LinkBatchId, RecordId, NextProcess.ProcessId, ActiveRoleCls.RoleId, ActiveRoleCls.RoleName, ComeFrom, ComeFromName, ComeFromOfficeCode, ComeFrom, ComeFromOfficeCode, Subject, RecordNote, PreviewUrl, PreviewTarget, "", LinkId, XmlData, StartPointProcess, NextProcess, linkCls.NextViewParam, ComeFromOfficeCode, EmployeeCreated, ComeFromRoleCls,
                  DeleteBeforeNext,
                  null,
                  "to",
                  0,
                  linkCls.ProcessDays,
                  PriorityId,
                  PriorityText,
                  ExpireDate,
                  LinkType,
                  ReturnLinkId,
                  Owner,
                  ExtraInfo,
                  ExtraData,
                  1,
                  SendToUsers,
                  0);



                //string WorkflowHasReceivedId = System.Guid.NewGuid().ToString();
                ////doan nay nhet vao task cua thang nao nhan
                //string ReceivedCommandText = "Insert into [TableWorkflowHasReceived]([WorkflowHasReceivedId],[Subject], [Description], [frkWorkflowDefId], [ReceivedDate], [SendFromUser], [Owner], [Comment], [HasProcessed], [RecordId], [ObjectType], [frkWorkflowActionId], [frkBatchId], OwnerRoleId) values (@WorkflowHasReceivedId,@Subject, @Description, @frkWorkflowDefId, GetDate(), @SendFromUser, @Owner, @Comment, 0, @RecordId, @ObjectType, @frkWorkflowActionId, @frkBatchId, @OwnerRoleId)";
                ////doan nay nhet vao Receivedto
                //DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                //        dbTransaction,
                //        ReceivedCommandText,
                //        new Model.DatabaseParamCls[]{
                //            new Model.DatabaseParamCls("WorkflowHasReceivedId",WorkflowHasReceivedId),
                //            new Model.DatabaseParamCls("Subject",Subject),
                //            new Model.DatabaseParamCls("Description",RecordNote),
                //            new Model.DatabaseParamCls("frkWorkflowDefId",WorkflowDefId),
                //            new Model.DatabaseParamCls("SendFromUser",ComeFrom),
                //            new Model.DatabaseParamCls("Owner",WebSessionUtility.GetCurrentLoginUser().LoginName),
                //            new Model.DatabaseParamCls("Comment",RecordNote),
                //            new Model.DatabaseParamCls("RecordId",RecordId),
                //            new Model.DatabaseParamCls("ObjectType",ExtraInfo),
                //            new Model.DatabaseParamCls("frkWorkflowActionId",oInsertDatabaseReturnCls.WorkflowActionId),
                //            new Model.DatabaseParamCls("frkBatchId",BatchId),
                //            new Model.DatabaseParamCls("OwnerRoleId",ComeFromRoleId),
                //    }, CommandType.Text);

            }
            catch (Exception ex)
            {
                if (!HasTrans)
                {
                    dbTransaction.Rollback();
                }
                throw (ex);
            }
            if (!HasTrans)
            {
                dbTransaction.Commit();
            }

            return BatchId;
        }


        public string StartWorkFlow(
            Model.WsInParamCls oWsInParamCls,
            System.Data.Common.DbTransaction dbTransaction,
            string XmlWorkflowData,
            string Id,
            string GroupBatchId,
            string BatchId,
            string ComeFrom,
            string ComeFromName,
            string ComeFromOfficeCode,
            string ComeFromRoleId,
            string RecordId,
            string Subject,
            string RecordNote,
            string PreviewUrl,
            string PreviewTarget,
            int DeleteBeforeNext,
            string PriorityId,
            string PriorityText,
            DateTime ExpireDate,
            string LinkType,
            string ReturnLinkId,
            string Owner,
            string ExtraInfo,
            string ExtraData,
            string SendToUsers)
        {
            return StartWorkFlow(oWsInParamCls, dbTransaction, XmlWorkflowData, Id, GroupBatchId, BatchId, ComeFrom, ComeFromName, ComeFromOfficeCode, ComeFromRoleId, RecordId, Subject, RecordNote, "", PreviewUrl, PreviewTarget, DeleteBeforeNext, PriorityId, PriorityText, ExpireDate, LinkType, ReturnLinkId, Owner, ExtraInfo, ExtraData, SendToUsers);
        }


        public string StartWorkFlowWithProcess(
            Model.WsInParamCls oWsInParamCls,
            System.Data.Common.DbTransaction dbTransaction,
            WorkFlowApp wfa,
            string Id,
            string ProcessId,
            string GroupBatchId,
            string BatchId,
            string ComeFrom,
            string ComeFromName,
            string ComeFromOfficeCode,
            string ComeFromRoleId,
            string RecordId,
            string Subject,
            string RecordNote,
            string PreviewUrl,
            string PreviewTarget,
            int DeleteBeforeNext,
            string PriorityId,
            string PriorityText,
            DateTime ExpireDate,
            string LinkType,
            string ReturnLinkId,
            string Owner,
            string ExtraInfo,
            string ExtraData,
            string SendToUsers)
        {
            return StartWorkFlowWithProcess(
                oWsInParamCls,
                dbTransaction,
                wfa,
                Id,
                ProcessId,
                GroupBatchId,
                BatchId,
                ComeFrom,
                ComeFromName,
                ComeFromOfficeCode,
                ComeFromRoleId,
                RecordId,
                Subject,
                RecordNote,
                "",
                PreviewUrl,
                PreviewTarget,
                DeleteBeforeNext,
                PriorityId,
                PriorityText,
                ExpireDate,
                LinkType,
                ReturnLinkId,
                Owner,
                ExtraInfo,
                ExtraData,
                SendToUsers);
        }

        public LinkCls GetLink(WorkFlowApp wfa, string LinkId)
        {
            for (int iIndex = 0; iIndex < wfa.ArrayLinks.Count; iIndex++)
            {
                LinkCls linkCls = (LinkCls)wfa.ArrayLinks[iIndex];
                if (linkCls.LinkId.Equals(LinkId))
                {
                    return linkCls;
                }
            }
            return null;
        }


        public void RunScript(
            Model.WsInParamCls oWsInParamCls,
            WorkFlowApp wfa,
            System.Data.Common.DbTransaction dbTransaction,
            string BatchId,
            string RecordId,
            string LinkId)
        {
            bool HasTrans = dbTransaction != null;
            if (!HasTrans)
            {
                //SqlConnection sqlConnection = new SqlConnection(ConnectionString);
                //sqlConnection.Open();
                //sqlTransaction = sqlConnection.BeginTransaction();
                dbTransaction = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).BeginTransaction();
            }
            //SqlCommand sqlCommand = sqlTransaction.Connection.CreateCommand();
            //sqlCommand.Transaction = sqlTransaction;
            try
            {
                LinkCls linkCls = GetLink(wfa, LinkId);

                //sqlCommand.Parameters.Clear();
                string Query = linkCls.targetAction.Trim();
                if (Query.Trim().Length > 0)
                {
                    Query = Query.Replace("@RecordId", "'" + RecordId + "'");
                    Query = Query.Replace("@BatchId", "'" + BatchId + "'");
                    //sqlCommand.CommandText = Query;
                    //sqlCommand.ExecuteNonQuery();
                    DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(dbTransaction, Query);
                }
                if (!HasTrans)
                {
                    dbTransaction.Commit();
                }
            }
            catch (Exception ex)
            {
                if (!HasTrans)
                {
                    dbTransaction.Rollback();
                }
                throw (ex);
            }
        }


        public string GetParentId(Model.WsInParamCls oWsInParamCls, string Id)
        {
            string CommandText = "select LinkParentId from TableWorkflowAction where Id='" + Id + "'";
            DataTable dtResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(CommandText);
            if (dtResult.Rows.Count == 0) return null;
            if (dtResult.Rows[0]["LinkParentId"] == DBNull.Value) return null;
            string ParentId = (string)dtResult.Rows[0]["LinkParentId"];

            return ParentId;
        }


        public static DataTable ReadingWorkflowDefDelegateTask(string ConnectionString)
        {
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;
            string CommandText = " select WorkflowDefId, WorkFlowName from TableWorkflowDef where 1=1 ";
            CommandText +=
                " and WorkflowDefId in (select WorkflowDefId from TableWorkflowAction where [sent]=0 and ProcessDone=0 and EmployeeLoginName in (select Owner from [TableDelegatePermissionUser] join TableDelegatePermission on TableDelegatePermission.DelegatePermissionId=frkDelegatePermissionId  where [Active]=1 and LoginName=@LoginName)";
            CommandText += " ) order by WorkflowDefId";
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
            CommandText, new DatabaseParamCls[] 
            { 
                new DatabaseParamCls("LoginName", WebSessionUtility.GetCurrentLoginUser().LoginName)
            });

            return ds.Tables[0];
        }

        public static DataTable ReadingDelegateTasks(
             string ConnectionString,
             string WorkflowDefId,
             string LoginName)
        {
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;

            string ProcessType = "to";
            string Query = "select Id,WorkflowDefId,ProcessType,EmployeeLoginName, Subject,RecordNote,ActionDate,ComeFrom,ComeFromName,PreviewUrl,DelayNote,Owner,ExtraInfo,RecordId,PreviewTarget=IsNull(PreviewTarget,'_self'),WorkflowDefName,ExpireDate,toProcessName from TableWorkFlowAction where ProcessType='" + ProcessType + "' and [sent]=0 and ProcessDone=0 and EmployeeLoginName in (select Owner from [TableDelegatePermissionUser] join TableDelegatePermission on TableDelegatePermission.DelegatePermissionId=frkDelegatePermissionId where [Active]=1 and LoginName=@LoginName)";
            if (!String.IsNullOrEmpty(WorkflowDefId))
            {
                Query += " and WorkflowDefId='" + WorkflowDefId + "'";
            }

            Query += " order by [ActionDate]";

            DataTable dtResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(
                Query,
                new DatabaseParamCls[]{
                    new DatabaseParamCls("LoginName",LoginName),
                });

            return dtResult;
        }


        public static DataTable ReadingMyTasks(
            string ConnectionString,
            string ProcessType,
            string WorkflowDefId,
            string LoginName,
            string RoleId,
            string Keyword)
        {
            //*,AttachedDocuments=(select count(WorkflowActionAttachFileId) from TableWorkFlowActionAttachFile where frkWorkflowActionId=Id)
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;
            string Query = "select Id,WorkflowDefId,ProcessType,Subject,RecordNote,ActionDate,ComeFrom,ComeFromName,PreviewUrl,DelayNote,Owner,ExtraInfo,RecordId,PreviewTarget=IsNull(PreviewTarget,'_self'),WorkflowDefName,ExpireDate,toProcessName from TableWorkFlowAction where [sent]=0 and ProcessDone=0 and EmployeeLoginName=@LoginName and toRole=@RoleId and ProcessType=@ProcessType";
            if (!String.IsNullOrEmpty(WorkflowDefId))
            {
                Query += " and WorkflowDefId='" + WorkflowDefId + "'";
            }
            Keyword = FunctionUtilities.CorrectForSearch(Keyword);
            if (!string.IsNullOrEmpty(Keyword))
            {
                Query += " and Subject like N'%" + Keyword + "%'";
            }
            Query += " order by [ActionDate] DESC";

            DataTable dtResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(
                Query,
                new Model.DatabaseParamCls[]{
                    new Model.DatabaseParamCls("LoginName",LoginName),
                    new Model.DatabaseParamCls("RoleId",RoleId),
                    new Model.DatabaseParamCls("ProcessType",ProcessType)
                });

            return dtResult;
        }

        public static DataTable ReadingRunningWorkflowTaskForReminder(
            string ConnectionString,
            string LoginName)
        {
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;
            //string Query = "select TableRunningWorkflowTask.* from TableRunningWorkflowTaskUser " +
            //               "        join TableRunningWorkflowTask on TableRunningWorkflowTask.RunningWorkflowTaskId=frkRunningWorkflowTaskId" +
            //               "     where LoginName=@LoginName"+
            //               "        order by [CurrentDate]";
            string FromDate = (new System.DateTime(System.DateTime.Now.Year, System.DateTime.Now.Month, System.DateTime.Now.Day)).ToString("MM/dd/yyyy") + " 00:00";
            string ToDate = (new System.DateTime(System.DateTime.Now.Year, System.DateTime.Now.Month, System.DateTime.Now.Day)).AddDays(2).ToString("MM/dd/yyyy") + " 23:59";
            string Query = "select ObjectRecordId=RecordId,WorkFlowDefId=frkWorkflowDefId,Subject,Description,StartDate=DueDate,ObjectType,PreviewUrl='#' from TableWorkflowHasReceived where HasProcessed=0 and owner=@LoginName and not DueDate is null and DueDate between '" + FromDate + "' and '" + ToDate + "'";
            DataTable dtResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(Query, new DatabaseParamCls[] { new DatabaseParamCls("LoginName", LoginName) });
            return dtResult;
        }

        public static DataTable ReadingRunningWorkflowTask(
          string ConnectionString,
          string WorkflowDefId)
        {
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;
            string Query = "select * from TableRunningWorkflowTask where 1=1";
            if (!String.IsNullOrEmpty(WorkflowDefId))
            {
                Query += " and WorkflowDefId='" + WorkflowDefId + "'";
            }
            Query += " order by [CurrentDate]";

            DataTable dtResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(Query, null);
            return dtResult;
        }


        public static void DeleteRunningWorkflowTask(
          string ConnectionString,
          string RunningWorkflowTaskId)
        {
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;
            string Query =
                " Delete from TableWorkflowAction where RunningWorkflowTaskId=@RunningWorkflowTaskId;" +
                " Delete from TableRunningWorkflowTask where RunningWorkflowTaskId=@RunningWorkflowTaskId";
            DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(Query, new DatabaseParamCls[] { new DatabaseParamCls("RunningWorkflowTaskId", RunningWorkflowTaskId) });
        }

        //public static void DeleteWorkflowTaskHasSent(
        //  string ConnectionString,
        //  string WorkflowHasSentId)
        //{
        //    Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
        //    oWsInParamCls.ConnectionString = ConnectionString;
        //    string Query =
        //        " Update TableWorkflowAction set frkWorkflowHasSentId=null where frkWorkflowHasSentId=@WorkflowHasSentId;" +
        //        " Delete from TableWorkflowHasSent where WorkflowHasSentId=@WorkflowHasSentId";
        //    DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(Query, new DatabaseParamCls[] { new DatabaseParamCls("WorkflowHasSentId", WorkflowHasSentId) });
        //}

        //public static void DeleteWorkflowTaskHasReceived(
        //  string ConnectionString,
        //  string WorkflowHasReceivedId)
        //{
        //    Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
        //    oWsInParamCls.ConnectionString = ConnectionString;
        //    string Query =
        //        //" Update TableWorkflowAction set frkWorkflowHasReceivedId=null where frkWorkflowHasReceivedId=@WorkflowHasReceivedId;" +
        //        " Delete from TableWorkflowHasReceived where WorkflowHasReceivedId=@WorkflowHasReceivedId";
        //    DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(Query, new DatabaseParamCls[] { new DatabaseParamCls("WorkflowHasReceivedId", WorkflowHasReceivedId) });
        //}

        public static DataSet ReadingMyTask(
            Model.WsInParamCls oWsInParamCls,
            string WorkflowDefId,
            string EmployeeId,
            string RoleId)
        {
            string Query = " select *,(select [Description] from TableData \r\n"+
                           " where DataId = TableWorkFlowAction.RecordId) as [Description] \r\n" +
                           " from TableWorkFlowAction where [sent]=0 and ProcessDone=0 and EmployeeId=@EmployeeId and toRole=@RoleId";
            if (!string.IsNullOrEmpty(WorkflowDefId))
            {
                Query += " and WorkflowDefId='" + WorkflowDefId + "'";
            }
            Query += " order by [ActionDate]";

            DataSet dsResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                Query,
                new Model.DatabaseParamCls[]{
                    new Model.DatabaseParamCls("EmployeeId",EmployeeId),
                    new Model.DatabaseParamCls("RoleId",RoleId)
                });

            return dsResult;
        }


        public static DataSet ReadingMyTaskForCat(
            Model.WsInParamCls oWsInParamCls,
            string WorkflowDefId,
            string EmployeeId,
            string RoleId,
            string CatId)
        {
            string Query = "select * from TableWorkFlowAction where [sent]=0 and ProcessDone=0 and EmployeeId=@EmployeeId and toRole=@RoleId ";
            if (!string.IsNullOrEmpty(CatId))
            {
                Query += " and RecordId in (select frkDataId from TableDataCategory where frkGroupDataCategoryId=@CatId)";
            }
            if (!string.IsNullOrEmpty(WorkflowDefId))
            {
                Query += " and WorkflowDefId='" + WorkflowDefId + "'";
            }
            Query += " order by [ActionDate]";

            DataSet dsResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                Query,
                new Model.DatabaseParamCls[]{
                    new Model.DatabaseParamCls("EmployeeId",EmployeeId),
                    new Model.DatabaseParamCls("RoleId",RoleId),
                    new Model.DatabaseParamCls("CatId",CatId),
                });

            return dsResult;
        }

        public static void ReadingMyTask(
            Model.WsInParamCls oWsInParamCls,
            ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string LoginName = oWsInParamCls.LoginName;
            string WorkflowDefId = oWsInParamCls.KeyId;
            string RoleId = oWsInParamCls.Keyword;
            DataSet ds = ReadingMyTask(oWsInParamCls, WorkflowDefId, LoginName, RoleId);
            oWsReturnParamCls.dsResult = ds;
        }

        public void ReadingSentTasks(
             Model.WsInParamCls oWsInParamCls,
             ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string LoginName = oWsInParamCls.LoginName;
            string WorkflowDefId = oWsInParamCls.KeyId;
            string RoleId = oWsInParamCls.Keyword;
            string CommandText = "select * from TableWorkFlowAction where [Sent]=1 and EmployeeLoginName=@LoginName and toRole=@RoleId";
            if (WorkflowDefId.Trim().Length > 0)
            {
                CommandText += " and WorkflowDefId='" + WorkflowDefId + "'";
            }
            CommandText += " order by [ActionDate]";

            DataSet dsResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                CommandText,
                new Model.DatabaseParamCls[]{
                    new Model.DatabaseParamCls("LoginName",LoginName),
                    new Model.DatabaseParamCls("RoleId",RoleId)
                });

            oWsReturnParamCls.dsResult = dsResult;
        }


        public void ReadingWaitTasks(
             Model.WsInParamCls oWsInParamCls,
             ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string LoginName = oWsInParamCls.LoginName;
            string WorkflowDefId = oWsInParamCls.KeyId;
            string RoleId = oWsInParamCls.Keyword;
            string CommandText = "select * from TableWorkFlowAction where [ProcessDone]=0 and [WaitingTasks]<>0  and EmployeeLoginName=@LoginName and toRole=@RoleId";
            if (WorkflowDefId.Trim().Length > 0)
            {
                CommandText += " and WorkflowDefId='" + WorkflowDefId + "'";
            }
            CommandText += " order by [ActionDate]";

            DataSet dsResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
               CommandText,
               new Model.DatabaseParamCls[]{
                    new Model.DatabaseParamCls("LoginName",LoginName),
                    new Model.DatabaseParamCls("RoleId",RoleId)
                });

            oWsReturnParamCls.dsResult = dsResult;
        }


        public string GetXmlWorkflowDataFromDef(
            string ConnectionString,
            string WorkflowDefId)
        {
            WsInParamCls oWsInParamCls = new WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;
            string Query = "select [XmlData] from [TableWorkflowDef] where WorkflowDefId=@WorkflowDefId";
            DataSet dsResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                Query,
                new Model.DatabaseParamCls[]{
                    new Model.DatabaseParamCls("WorkflowDefId",WorkflowDefId)
                });

            if (dsResult.Tables[0].Rows.Count == 0) throw new Exception("Không tìm thấy workflow id [" + WorkflowDefId + "]");
            return (string)dsResult.Tables[0].Rows[0]["XmlData"];
        }

        public string GetXmlWorkflowData(
            string ConnectionString,
            string WorkflowActionId)
        {
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;
            return GetXmlWorkflowData(oWsInParamCls, WorkflowActionId);
        }


        public string GetXmlWorkflowData(
            Model.WsInParamCls oWsInParamCls,
            string WorkflowActionId)
        {
            string LoginName = oWsInParamCls.LoginName;
            string WorkflowDefId = oWsInParamCls.KeyId;
            string Query = " select XmlWorkflowData from TableWorkFlowAction "+
                           "    join TableRunningWorkflowTask on TableRunningWorkflowTask.RunningWorkflowTaskId=TableWorkflowAction.RunningWorkflowTaskId"+
                           " where Id=@WorkflowActionId";
            DataSet dsResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                Query,
                new Model.DatabaseParamCls[]{
                    new Model.DatabaseParamCls("WorkflowActionId",WorkflowActionId)
                });

            return (string)dsResult.Tables[0].Rows[0]["XmlWorkflowData"];
        }



        public string ServerSideGetExtraInfo(
            string ConnectionString,
            string WorkflowActionId)
        {
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;
            return ServerSideGetExtraInfo(oWsInParamCls, WorkflowActionId);
        }


        public string ServerSideGetExtraInfo(
            Model.WsInParamCls oWsInParamCls,
            string WorkflowActionId)
        {
            string LoginName = oWsInParamCls.LoginName;
            string WorkflowDefId = oWsInParamCls.KeyId;
            string Query = "select ExtraInfo=IsNull(ExtraInfo,'') from TableWorkFlowAction where Id=@WorkflowActionId";
            DataSet dsResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                Query,
                new Model.DatabaseParamCls[]{
                    new Model.DatabaseParamCls("WorkflowActionId",WorkflowActionId)
                });

            return (string)dsResult.Tables[0].Rows[0]["ExtraInfo"];
        }

        RoleCls CreateRoleModel(
            Model.WsInParamCls oWsInParamCls,
            string RoleId)
        {
            string Query = "select * from TableRole where RoleId=@RoleId";
            DataSet dsResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(
                Query,
                new Model.DatabaseParamCls[]{
                    new Model.DatabaseParamCls("RoleId",RoleId)
                });
            if (dsResult.Tables[0].Rows.Count == 0) return null;

            RoleCls oRoleCls = new RoleCls();
            oRoleCls.RoleId = (string)dsResult.Tables[0].Rows[0]["RoleId"];
            oRoleCls.RoleCode = (string)dsResult.Tables[0].Rows[0]["RoleCode"];
            oRoleCls.RoleName = (string)dsResult.Tables[0].Rows[0]["RoleName"];
            return oRoleCls;
        }


        //public string ServerSideGetViewUsersByLoginName(
        //    string PathRoot,
        //    string ConnectionString,
        //    string WorkFlowDefId,
        //    string LinkId)
        //{
        //    string ViewUsers = "";
        //    string XmlData = GetXmlWorkflowDataFromDef(ConnectionString, WorkFlowDefId);
        //    WorkFlowApp wfa = new WorkFlowApp(XmlData);
        //    LinkCls oLinkCls = wfa.GetLink(LinkId);
        //    for (int iRole = 0; iRole < oLinkCls.ViewRoleIds.Length; iRole++)
        //    {
        //        EmployeeCls[] Employees = wfa.GetUsersInRole(oLinkCls.ViewRoleIds[iRole]);
        //        for (int iIndex = 0; iIndex < Employees.Length; iIndex++)
        //        {
        //            if (string.IsNullOrEmpty(ViewUsers) == false) ViewUsers = ViewUsers + ";";
        //            ViewUsers = ViewUsers + Employees[iIndex].LoginName;
        //        }
        //    }
        //    return ViewUsers;
        //}

        //public string ServerSideGetViewUsersByFullName(
        //    string PathRoot,
        //    string ConnectionString,
        //    string WorkFlowDefId,
        //    string LinkId)
        //{
        //    string ViewUsers = "";
        //    string XmlData = GetXmlWorkflowDataFromDef(ConnectionString, WorkFlowDefId);
        //    WorkFlowApp wfa = new WorkFlowApp(XmlData);
        //    LinkCls oLinkCls = wfa.GetLink(LinkId);
        //    for (int iRole = 0; iRole < oLinkCls.ViewRoleIds.Length; iRole++)
        //    {
        //        EmployeeCls[] Employees = wfa.GetUsersInRole(oLinkCls.ViewRoleIds[iRole]);
        //        for (int iIndex = 0; iIndex < Employees.Length; iIndex++)
        //        {
        //            if (string.IsNullOrEmpty(ViewUsers) == false) ViewUsers = ViewUsers + ";";
        //            ViewUsers = ViewUsers + Employees[iIndex].FullName;
        //        }
        //    }
        //    return ViewUsers;
        //}

        public WorkflowActionInfoCls ServerSideCheckStartWorkFlowRecord(
            string ConnectionString,
            string WorkFlowActionId)
        {
            SqlConnection oSqlConnection = new SqlConnection(ConnectionString);
            oSqlConnection.Open();
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = "select StartWorkflowRecord=IsNull(StartWorkflowRecord,0),ExtraInfo=IsNull(ExtraInfo,''),SendToUsers=IsNull(SendToUsers,'') from TableWorkflowAction where Id=@WorkFlowActionId";
            oSqlCommand.Parameters.Add("@WorkFlowActionId", SqlDbType.VarChar).Value = WorkFlowActionId;
            DataTable dtResult = new DataTable();
            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            sqlda.Fill(dtResult);
            if (dtResult.Rows.Count == 0) return null;
            int StartWorkflowRecord = (int)dtResult.Rows[0]["StartWorkflowRecord"];
            WorkflowActionInfoCls oWorkflowActionInfoCls = new WorkflowActionInfoCls();
            oWorkflowActionInfoCls.StartWorkflowRecord = StartWorkflowRecord == 1;
            if (dtResult.Rows[0]["ExtraInfo"] != DBNull.Value)
            {
                oWorkflowActionInfoCls.ExtraInfo = (string)dtResult.Rows[0]["ExtraInfo"];
            }
            if (dtResult.Rows[0]["SendToUsers"] != DBNull.Value)
            {
                oWorkflowActionInfoCls.SendToUsers = (string)dtResult.Rows[0]["SendToUsers"];
            }
            return oWorkflowActionInfoCls;
        }

        //public string ServerSideGetToUsersByLoginName(
        //    string PathRoot,
        //    string ConnectionString,
        //    string WorkFlowDefId,
        //    string WorkFlowActionId,
        //    string LinkId)
        //{
        //    string ToUsers = "";
        //    string XmlData = GetXmlWorkflowDataFromDef(ConnectionString, WorkFlowDefId);
        //    WorkFlowApp wfa = new WorkFlowApp(XmlData);
        //    LinkCls oLinkCls = wfa.GetLink(LinkId);
        //    DataTable dtRole = new WorkflowBll().GetWfRoleInLink(PathRoot, ConnectionString, WorkFlowActionId, LinkId);
        //    ArrayList ArrayListRoles = new ArrayList();
        //    for (int iRole = 0; iRole < oLinkCls.RoleIds.Length; iRole++)
        //    {
        //        bool Ok = false;
        //        for (int iCheck = 0; iCheck < dtRole.Rows.Count; iCheck++)
        //        {
        //            string iRoleId = (string)dtRole.Rows[iCheck]["RoleId"];
        //            if (iRoleId.Equals(oLinkCls.RoleIds[iRole]))
        //            {
        //                Ok = true;
        //                break;
        //            }
        //        }
        //        if (Ok)
        //        {
        //            ArrayListRoles.Add(oLinkCls.RoleIds[iRole]);
        //        }
        //    }
        //    for (int iRole = 0; iRole < ArrayListRoles.Count; iRole++)
        //    {
        //        string iRoleId = (string)ArrayListRoles[iRole];
        //        EmployeeCls[] Employees = wfa.GetUsersInRole(iRoleId);
        //        for (int iIndex = 0; iIndex < Employees.Length; iIndex++)
        //        {
        //            if (string.IsNullOrEmpty(ToUsers) == false) ToUsers = ToUsers + ";";
        //            ToUsers = ToUsers + Employees[iIndex].LoginName;
        //        }
        //    }


        //    return ToUsers;
        //}



        //public string ServerSideGetToUsersByFullName(
        //    string PathRoot,
        //    string ConnectionString,
        //    string WorkFlowDefId,
        //    string WorkFlowActionId,
        //    string LinkId)
        //{
        //    string ToUsers = "";
        //    string XmlData = GetXmlWorkflowDataFromDef(ConnectionString, WorkFlowDefId);
        //    WorkFlowApp wfa = new WorkFlowApp(XmlData);
        //    LinkCls oLinkCls = wfa.GetLink(LinkId);
        //    DataTable dtRole = new WorkflowBll().GetWfRoleInLink(PathRoot, ConnectionString, WorkFlowActionId, LinkId);
        //    ArrayList ArrayListRoles = new ArrayList();
        //    for (int iRole = 0; iRole < oLinkCls.RoleIds.Length; iRole++)
        //    {
        //        bool Ok = false;
        //        for (int iCheck = 0; iCheck < dtRole.Rows.Count; iCheck++)
        //        {
        //            string iRoleId = (string)dtRole.Rows[iCheck]["RoleId"];
        //            if (iRoleId.Equals(oLinkCls.RoleIds[iRole]))
        //            {
        //                Ok = true;
        //                break;
        //            }
        //        }
        //        if (Ok)
        //        {
        //            ArrayListRoles.Add(oLinkCls.RoleIds[iRole]);
        //        }
        //    }
        //    for (int iRole = 0; iRole < ArrayListRoles.Count; iRole++)
        //    {
        //        string iRoleId = (string)ArrayListRoles[iRole];
        //        EmployeeCls[] Employees = wfa.GetUsersInRole(iRoleId);
        //        for (int iIndex = 0; iIndex < Employees.Length; iIndex++)
        //        {
        //            if (string.IsNullOrEmpty(ToUsers) == false) ToUsers = ToUsers + ";";
        //            ToUsers = ToUsers + Employees[iIndex].FullName;
        //        }
        //    }


        //    return ToUsers;
        //}

        public DataTable GetWfRoleInLink(
            string PathRoot,
            string ConnectionString,
            string WorkFlowActionId,
            string LinkId)
        {
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.PathRoot = PathRoot;
            oWsInParamCls.ConnectionString = ConnectionString;
            return GetWfRoleInLink(oWsInParamCls, WorkFlowActionId, LinkId).Tables[0];
        }


        public DataTable GetWfRoleInLinkForView(
           string PathRoot,
           string ConnectionString,
           string WorkFlowActionId,
           string LinkId)
        {
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.PathRoot = PathRoot;
            oWsInParamCls.ConnectionString = ConnectionString;
            return GetWfRoleInLinkForView(oWsInParamCls, WorkFlowActionId, LinkId).Tables[0];
        }

        public DataSet GetWfRoleInLink(
            Model.WsInParamCls oWsInParamCls,
            string WorkFlowActionId,
            string LinkId)
        {
            DataTable dtInfo = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet("select * from TableWorkflowAction where Id=@WorkFlowActionId",
               new Model.DatabaseParamCls[]{
                    new Model.DatabaseParamCls("WorkFlowActionId",WorkFlowActionId)
                });
            //if (dtInfo.Rows.Count == 0) throw new Exception("Quy trình đã kết thúc! Không thực hiện chuyển được!");
            string CurrentRoleId = dtInfo.Rows[0]["toRole"].ToString();

            string XmlWorkflowData = GetXmlWorkflowData(oWsInParamCls, WorkFlowActionId);
            WorkFlowApp wfa = CreateWorkFlowApp(XmlWorkflowData);
            LinkCls oLinkCls = wfa.GetLink(LinkId);
            DataSet dsRole = new DataSet();
            dsRole.Tables.Add("Info");
            dsRole.Tables["Info"].Columns.Add("RoleId");
            dsRole.Tables["Info"].Columns.Add("RoleName");
            DataSet dsRoleRelationTemplate = null;
            if (!String.IsNullOrEmpty(oLinkCls.RoleRelationTemplateId))
            {
                dsRoleRelationTemplate = new DataSet();
                dsRoleRelationTemplate.ReadXml(new StringReader(oLinkCls.RoleRelationTemplateXmlData));

                //doan nay kiem tra xem co relation template role hay khong
                if (dsRoleRelationTemplate != null)
                {
                    //kiem tra nhung thang nao nam trong sub-thoi...!
                    for (int iIndexCheck = 0; iIndexCheck < dsRoleRelationTemplate.Tables[0].Rows.Count; iIndexCheck++)
                    {
                        string frkParentRoleId = (string)dsRoleRelationTemplate.Tables[0].Rows[iIndexCheck]["FromRoleId"];
                        string frkChildRoleId = (string)dsRoleRelationTemplate.Tables[0].Rows[iIndexCheck]["ToRoleId"];
                        if (frkParentRoleId.Equals(CurrentRoleId))//dung thang can lay duong link
                        {
                            RoleCls oRoleCls = CreateRoleModel(oWsInParamCls, frkChildRoleId);
                            if (oRoleCls != null)
                            {
                                dsRole.Tables["Info"].Rows.Add(new object[]{
                                    oRoleCls.RoleId,oRoleCls.RoleName
                            });
                            }
                            //break;
                        }
                    }
                }
            }
            else
            {
                for (int iIndex = 0; iIndex < oLinkCls.RoleIds.Length; iIndex++)
                {
                    dsRole.Tables["Info"].Rows.Add(new object[]{
                             oLinkCls.RoleIds[iIndex],oLinkCls.RoleNames[iIndex]
                        });
                }
            }
            return dsRole;
        }



        public DataSet GetWfRoleInLinkForView(
            Model.WsInParamCls oWsInParamCls,
            string WorkFlowActionId,
            string LinkId)
        {
            DataTable dtInfo = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet("select * from TableWorkflowAction where Id=@WorkFlowActionId",
               new Model.DatabaseParamCls[]{
                    new Model.DatabaseParamCls("WorkFlowActionId",WorkFlowActionId)
                });
            //if (dtInfo.Rows.Count == 0) throw new Exception("Quy trình đã kết thúc! Không thực hiện chuyển được!");
            string CurrentRoleId = dtInfo.Rows[0]["toRole"].ToString();

            string XmlWorkflowData = GetXmlWorkflowData(oWsInParamCls, WorkFlowActionId);
            WorkFlowApp wfa = CreateWorkFlowApp(XmlWorkflowData);
            LinkCls oLinkCls = wfa.GetLink(LinkId);
            DataSet dsRole = new DataSet();
            dsRole.Tables.Add("Info");
            dsRole.Tables["Info"].Columns.Add("RoleId");
            dsRole.Tables["Info"].Columns.Add("RoleName");
            DataSet dsRoleRelationTemplate = null;
            if (!String.IsNullOrEmpty(oLinkCls.ViewRoleRelationTemplateId))
            {
                dsRoleRelationTemplate = new DataSet();
                dsRoleRelationTemplate.ReadXml(new StringReader(oLinkCls.ViewRoleRelationTemplateXmlData));

                //doan nay kiem tra xem co relation template role hay khong
                if (dsRoleRelationTemplate != null)
                {
                    //kiem tra nhung thang nao nam trong sub-thoi...!
                    for (int iIndexCheck = 0; iIndexCheck < dsRoleRelationTemplate.Tables[0].Rows.Count; iIndexCheck++)
                    {
                        string frkParentRoleId = (string)dsRoleRelationTemplate.Tables[0].Rows[iIndexCheck]["FromRoleId"];
                        string frkChildRoleId = (string)dsRoleRelationTemplate.Tables[0].Rows[iIndexCheck]["ToRoleId"];
                        if (frkParentRoleId.Equals(CurrentRoleId))//dung thang can lay duong link
                        {
                            RoleCls oRoleCls = CreateRoleModel(oWsInParamCls, frkChildRoleId);
                            if (oRoleCls != null)
                            {
                                dsRole.Tables["Info"].Rows.Add(new object[]{
                                    oRoleCls.RoleId,oRoleCls.RoleName
                            });
                            }
                            //break;
                        }
                    }
                }
            }
            else
            {
                for (int iIndex = 0; iIndex < oLinkCls.ViewRoleIds.Length; iIndex++)
                {
                    dsRole.Tables["Info"].Rows.Add(new object[]{
                             oLinkCls.ViewRoleIds[iIndex],oLinkCls.ViewRoleNames[iIndex]
                        });
                }
            }
            return dsRole;
        }

        public void GetWfRoleInLink(
           Model.WsInParamCls oWsInParamCls,
           ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string WorkFlowActionId = oWsInParamCls.Xml;
            string LinkId = oWsInParamCls.KeyId;

            DataSet dsRoles = GetWfRoleInLink(oWsInParamCls, WorkFlowActionId, LinkId);
            oWsReturnParamCls.dsResult = dsRoles;
        }



        //public DataTable GetWfUsersInRole(
        //    string PathRoot,
        //    string ConnectionString,
        //    string LoginName,
        //    string WorkFlowActionId,
        //    string RoleId)
        //{
        //    Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
        //    oWsInParamCls.KeyId = WorkFlowActionId;
        //    oWsInParamCls.LoginName = LoginName;
        //    oWsInParamCls.PathRoot = PathRoot;
        //    oWsInParamCls.ConnectionString = ConnectionString;
        //    return GetWfUsersInRole(oWsInParamCls, WorkFlowActionId, RoleId).Tables[0];
        //}

        //public DataSet GetWfUsersInRole(
        //    Model.WsInParamCls oWsInParamCls,
        //    string WorkFlowActionId,
        //    string RoleId)
        //{
        //    string XmlWorkflowData = GetXmlWorkflowData(oWsInParamCls, WorkFlowActionId);
        //    WorkFlowApp wfa = CreateWorkFlowApp(XmlWorkflowData);
        //    EmployeeCls[] Employees = wfa.GetUsersInRole(RoleId);
        //    DataSet dsEmployees = new DataSet();
        //    dsEmployees.Tables.Add("Info");
        //    dsEmployees.Tables["Info"].Columns.Add("EmployeeId");
        //    dsEmployees.Tables["Info"].Columns.Add("LoginName");
        //    dsEmployees.Tables["Info"].Columns.Add("FullName");
        //    dsEmployees.Tables["Info"].Columns.Add("OfficeCode");
        //    dsEmployees.Tables["Info"].Columns.Add("ProcessType");
        //    for (int iIndex = 0; iIndex < Employees.Length; iIndex++)
        //    {
        //        dsEmployees.Tables["Info"].Rows.Add(new object[]{
        //            Employees[iIndex].EmployeeId,
        //            Employees[iIndex].LoginName,
        //            Employees[iIndex].FullName,
        //            Employees[iIndex].OfficeCode,
        //            Employees[iIndex].ProcessType,
        //        });
        //    }
        //    return dsEmployees;
        //}

        //public void GetWfUsersInRole(
        //    Model.WsInParamCls oWsInParamCls,
        //    ref Model.WsReturnParamCls oWsReturnParamCls)
        //{
        //    string WorkFlowActionId = oWsInParamCls.Xml;
        //    string RoleId = oWsInParamCls.KeyId;
        //    DataSet dsUsers = GetWfUsersInRole(oWsInParamCls, WorkFlowActionId, RoleId);
        //    oWsReturnParamCls.dsResult = dsUsers;
        //}




        public DataTable GetNextLinks(
            string PathRoot,
            string ConnectionString,
            string WorkFlowActionId,
            string LoginName,
            string CurrentLoginOffice)
        {
            WsInParamCls oWsInParamCls = new WsInParamCls();
            oWsInParamCls.PathRoot = PathRoot;
            oWsInParamCls.ConnectionString = ConnectionString;
            return GetNextLinks(oWsInParamCls, WorkFlowActionId, LoginName, CurrentLoginOffice).Tables[0];
        }

        public DataSet GetNextLinks(
            WsInParamCls oWsInParamCls,
            string WorkFlowActionId,
            string LoginName,
            string CurrentLoginOffice)
        {
            string Query =
                " select toRole,ProcessId,ViewParam,toOfficeCode,RecordId,XmlWorkflowData from TableWorkflowAction "+
                "       join TableRunningWorkflowTask on TableRunningWorkflowTask.RunningWorkflowTaskId=TableWorkflowAction.RunningWorkflowTaskId"+
                "   where Id=@WorkFlowActionId";
            DataTable dtInfo = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(
                Query,
                new Model.DatabaseParamCls[]{
                    new Model.DatabaseParamCls("WorkFlowActionId",WorkFlowActionId)
                });
            if (dtInfo.Rows.Count == 0) throw new Exception("Quy trình đã kết thúc! Không thực hiện chuyển được!");
            string RoleId = dtInfo.Rows[0]["toRole"].ToString();
            string XmlWorkflowData = dtInfo.Rows[0]["XmlWorkflowData"].ToString();
            string ProcessId = dtInfo.Rows[0]["ProcessId"].ToString();
            string ViewParam = dtInfo.Rows[0]["ViewParam"].ToString();
            string CurrentActiveOffice = dtInfo.Rows[0]["toOfficeCode"].ToString();
            string RecordId = dtInfo.Rows[0]["RecordId"].ToString();

            WorkFlowApp wfa = CreateWorkFlowApp(XmlWorkflowData);
            string DllWfServiceId = wfa.WorkFlowDefCls.DllWfServiceId;
            LinkCls[] Links = wfa.GetNextLinks(
                oWsInParamCls,
                DllWfServiceId,
                oWsInParamCls.PathRoot,
                RecordId,
                ProcessId,
                ViewParam,
                LoginName,
                RoleId,
                CurrentActiveOffice,
                CurrentLoginOffice);
            DataSet dsResult = new DataSet();
            dsResult.Tables.Add("Links");
            dsResult.Tables["Links"].Columns.Add("LinkId");
            dsResult.Tables["Links"].Columns.Add("LinkName");
            dsResult.Tables["Links"].Columns.Add("ButtonLink");
            dsResult.Tables["Links"].Columns.Add("SortIndex", typeof(int));
            dsResult.Tables["Links"].Columns.Add("SelectUser");
            dsResult.Tables["Links"].Columns.Add("LinkButtonStatusId");
            for (int iIndex = 0; iIndex < Links.Length; iIndex++)
            {
                dsResult.Tables[0].Rows.Add(new object[]{
                    Links[iIndex].LinkId,Links[iIndex].LinkName,Links[iIndex].ButtonLink, Links[iIndex].SortIndex,Links[iIndex].SelectUser,Links[iIndex].LinkButtonStatusId
                });
            }
            return dsResult;
        }

        public void GetNextLinks(
            Model.WsInParamCls oWsInParamCls,
            ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string XmlData = oWsInParamCls.Xml;
            DataSet ds = new DataSet();
            ds.ReadXml(new StringReader(XmlData));
            string WorkFlowActionId = ds.Tables[0].Rows[0]["WorkFlowActionId"].ToString();
            string LoginName = ds.Tables[0].Rows[0]["LoginName"].ToString();
            string CurrentLoginOffice = ds.Tables[0].Rows[0]["CurrentLoginOffice"].ToString();


            DataSet dsResult = GetNextLinks(
                oWsInParamCls,
                WorkFlowActionId,
                LoginName,
                CurrentLoginOffice);
            oWsReturnParamCls.dsResult = dsResult;
        }



        public EmployeeCls DetectFromEmployee(
            Model.WsInParamCls oWsInParamCls,
            WorkFlowApp wfa,
            string WorkflowActionId,
            string ReturnLinkId)
        {
            string SiteId = oWsInParamCls.SiteId;
            string CommandText = "";
            DataTable dtResult = null;
            if (String.IsNullOrEmpty(ReturnLinkId))
            {
                CommandText = "select LinkParentId from TableWorkflowAction where Id='" + WorkflowActionId + "'";
                dtResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(CommandText);
                if (dtResult.Rows.Count == 0) return null;
                if (dtResult.Rows[0]["LinkParentId"] == DBNull.Value) return null;

                string ParentId = (string)dtResult.Rows[0]["LinkParentId"];

                CommandText = "select EmployeeId,toRole,toRoleName,LinkId,WorkflowActionId=Id,ComeFrom,FromRole from TableWorkflowAction where Id='" + ParentId + "'";
                dtResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(CommandText);

                string EmployeeId = (string)dtResult.Rows[0]["EmployeeId"];
                string toRole = (string)dtResult.Rows[0]["toRole"];
                string toRoleName = (string)dtResult.Rows[0]["toRoleName"];
                EmployeeCls Found = CreateEmployeeModelFromUser(SiteId, EmployeeId);
                Found.ToRole = new RoleCls();
                Found.ToRole.RoleId = toRole;
                Found.ToRole.RoleName = toRoleName;
                Found.TempRoleId = new string[] { toRole };
                return Found;

            }
            else
            {
                CommandText = "select * from TableWorkflowAction where Id='" + WorkflowActionId + "'";
                dtResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(CommandText);
                if (dtResult.Rows.Count == 0) return null;

                string TempLinkId = "";
                if (dtResult.Rows[0]["LinkId"] != DBNull.Value)
                {
                    TempLinkId = (string)dtResult.Rows[0]["LinkId"];
                }
                if (TempLinkId.Equals(ReturnLinkId))
                {
                    string EmployeeId = (string)dtResult.Rows[0]["ComeFrom"];
                    string FromRole = (string)dtResult.Rows[0]["FromRole"];
                    string FromRoleName = (string)dtResult.Rows[0]["FromRoleName"];
                    EmployeeCls Found = CreateEmployeeModelFromUser(SiteId, EmployeeId);
                    Found.ToRole = new RoleCls();
                    Found.ToRole.RoleId = FromRole;
                    Found.ToRole.RoleName = FromRoleName;
                    Found.TempRoleId = new string[] { FromRole };
                    return Found;
                }
                else
                {
                    string ItemWorkflowActionId = (string)dtResult.Rows[0]["LinkParentId"];
                    return DetectFromEmployee(oWsInParamCls, wfa, ItemWorkflowActionId, ReturnLinkId);
                }
            }
        }

        bool CheckPrevTaskDone(Model.WsInParamCls oWsInParamCls, string WorkflowActionId)
        {
            DataTable dtInfo = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(
                "select LinkType from TableWorkFlowAction where LinkType='Parallel' and Sent=1 and LinkParentId='" + WorkflowActionId + "'");
            return dtInfo.Rows.Count == 0;
        }

        public class DoNextLinkRunAtServerReturnCls
        {
            public string Url;
            public bool IsLink = false;
            public string ReturnMessage = "";
        }

        public DoNextLinkRunAtServerReturnCls DoNextLinkRunAtServer(
            string SiteId,
            DbTransaction dbTransaction,
            string LinkId,
            string WorkflowActionId,
            string Note,
            string XmlUsers,
            string XmlData,
            string ProcessDays,
            string WorkflowFunction,
            string AttachFileSessionId,
            string AttachedDocumentIds,
            string FlashQueuePath,

            string ResponsibleId,
            string Responsible,
            string JoinerId,
            string Joiner)
        {
            SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = oSiteParam.ConnectionString;
            oWsInParamCls.SiteId = oSiteParam.SiteId;
            oWsInParamCls.PathRoot = oSiteParam.PathRoot;
            oWsInParamCls.HttpRoot = oSiteParam.HttpRoot;
            oWsInParamCls.LoginName = WebSessionUtility.GetCurrentLoginUser().LoginName;
            oWsInParamCls.RoleId = WebSessionUtility.GetCurrentLoginUser().RoleId;
            oWsInParamCls.SiteId = SiteId;
            return DoNextLink(oWsInParamCls, dbTransaction, LinkId, WorkflowActionId, Note, XmlUsers, XmlData, ProcessDays, WorkflowFunction, AttachFileSessionId, AttachedDocumentIds, FlashQueuePath, ResponsibleId, Responsible, JoinerId, Joiner);
        }


        public void CheckDoNextLinkRunAtServer(
            string SiteId,
            string WorkflowActionId)
        {
            SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = oSiteParam.ConnectionString;
            oWsInParamCls.SiteId = oSiteParam.SiteId;
            oWsInParamCls.PathRoot = oSiteParam.PathRoot;
            oWsInParamCls.HttpRoot = oSiteParam.HttpRoot;
            oWsInParamCls.LoginName = WebSessionUtility.GetCurrentLoginUser().LoginName;
            oWsInParamCls.RoleId = WebSessionUtility.GetCurrentLoginUser().RoleId;

            DataTable dtInfo = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(
                "select TOP 1 * from TableWorkFlowAction where Id='" + WorkflowActionId + "'");
            if (dtInfo.Rows.Count == 0)
            {
                throw new Exception("Quy trình đã xử lý hoặc không tìm thấy!");
            }
            int WaitingTasks = int.Parse(dtInfo.Rows[0]["WaitingTasks"].ToString());
            int Sent = int.Parse(dtInfo.Rows[0]["Sent"].ToString());
            if (Sent == 1) throw new Exception("Đã chuyển không thực hiện chuyển nữa!");
            if (Sent == 2) throw new Exception("Đã chuyển bởi người khác có cùng cấp không thực hiện chuyển nữa!");
            if (WaitingTasks > 0) throw new Exception("Task đang trong trạng thái chờ task khác hoàn thành trước khi được chuyển!");
            bool Check = CheckPrevTaskDone(oWsInParamCls, WorkflowActionId);
            if (Check == false)
            {
                throw new Exception("Task trước có kiểu giải quyết song song. Các task này chưa hoàn thành nên không thể chuyển được!");
            }
        }


        public void ServerSideDeleteWorkflowAction(
            string SiteId,
            string WorkflowActionId)
        {
            SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);
            Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
            oWsInParamCls.ConnectionString = oSiteParam.ConnectionString;
            oWsInParamCls.SiteId = oSiteParam.SiteId;
            oWsInParamCls.PathRoot = oSiteParam.PathRoot;
            oWsInParamCls.HttpRoot = oSiteParam.HttpRoot;
            oWsInParamCls.LoginName = WebSessionUtility.GetCurrentLoginUser().LoginName;
            oWsInParamCls.RoleId = WebSessionUtility.GetCurrentLoginUser().RoleId;

            DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                " Delete from TableWorkflowActionAttachFile where frkWorkflowActionId=@WorkflowActionId; " +
                " Delete from TableWorkflowAction where Id=@WorkflowActionId",
                new DatabaseParamCls[]{
                    new DatabaseParamCls("WorkflowActionId",WorkflowActionId)
                });
        }

        bool CheckExitsRunningWorkflowTask(Model.WsInParamCls oWsInParamCls, string RunningWorkflowTaskId)
        {
            DataTable dtCheck = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(
                " select  RunningWorkflowTaskId from TableRunningWorkflowTask where RunningWorkflowTaskId=@RunningWorkflowTaskId",
                new DatabaseParamCls[]{
                    new DatabaseParamCls("RunningWorkflowTaskId",RunningWorkflowTaskId)
                });
            return dtCheck.Rows.Count > 0;
        }

        public class TempAttachFile
        {
            public string WorkflowAttachFileId;
            public string RealFile;
            public byte[] Data;
            public string AttachedBy;
            public DateTime AttachedDate;
        }


        public void AddShareObjectToUser(
            SqlTransaction _SqlTransaction,
            string SiteId,
            string ObjectType,
            string ObjectId,
            string LoginName,
            string FullName)
        {
            if (string.IsNullOrEmpty(LoginName)) return;
            if (LoginName == null) LoginName = "";

            string SharedObjectId = System.Guid.NewGuid().ToString();
            string Query =
                " Delete from TableSharedObject where ObjectId=@ObjectId and LoginName=@LoginName;" +
                " Insert into TableSharedObject(SharedObjectId, LoginName, frkRoleId, FullName, ObjectId, [Type], [ObjectType]) values (@SharedObjectId, @LoginName, @frkRoleId, @FullName, @ObjectId, @Type, @ObjectType)";
            SqlCommand TempSqlCommand = _SqlTransaction.Connection.CreateCommand();
            TempSqlCommand.Transaction = _SqlTransaction;
            TempSqlCommand.CommandText = Query;

            TempSqlCommand.Parameters.Add("@SharedObjectId", SqlDbType.VarChar);
            TempSqlCommand.Parameters["@SharedObjectId"].Value = SharedObjectId;

            TempSqlCommand.Parameters.Add("@LoginName", SqlDbType.NVarChar);
            TempSqlCommand.Parameters["@LoginName"].Value = LoginName;

            TempSqlCommand.Parameters.Add("@frkRoleId", SqlDbType.VarChar);
            TempSqlCommand.Parameters["@frkRoleId"].Value = DBNull.Value;


            TempSqlCommand.Parameters.Add("@FullName", SqlDbType.NVarChar);
            TempSqlCommand.Parameters["@FullName"].Value = FullName;

            TempSqlCommand.Parameters.Add("@Type", SqlDbType.VarChar);
            TempSqlCommand.Parameters["@Type"].Value = "user";

            TempSqlCommand.Parameters.Add("@ObjectId", SqlDbType.VarChar);
            TempSqlCommand.Parameters["@ObjectId"].Value = ObjectId;

            TempSqlCommand.Parameters.Add("@ObjectType", SqlDbType.VarChar);
            TempSqlCommand.Parameters["@ObjectType"].Value = ObjectType;

            TempSqlCommand.ExecuteNonQuery();
        }


        public DoNextLinkRunAtServerReturnCls DoNextLink(
             Model.WsInParamCls oWsInParamCls,
             DbTransaction dbTransaction,
             string LinkId,
             string WorkflowActionId,
             string Note,
             string XmlUsers,
             string XmlData,
             string ProcessDays,
             string RunWorkflowFunction,
             string AttachFileSessionId,
             string AttachedDocumentIds,
             string FlashQueuePath,
             string ResponsibleId,
             string Responsible,
             string JoinerId,
             string Joiner)
        {
            string SiteId = oWsInParamCls.SiteId;
            SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);
            DoNextLinkRunAtServerReturnCls oDoNextLinkRunAtServerReturnCls = new DoNextLinkRunAtServerReturnCls();
            string[] AllAttachedDocumentIds = AttachedDocumentIds.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

            DataTable dtInfo = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(
               "select TOP 1 RunningWorkflowTaskId,GroupBatchId, BatchId," +
               "        toRole,RecordId,EmployeeLoginName,EmployeeId,Owner,ExtraInfo,Subject," +
               "        PreviewUrl,LinkType, PreviewTarget, EmployeeId, toOfficeCode, PriorityId, PriorityText, " +
               "        LinkBatchId, WorkflowStatus, WaitingTasks, Sent, ExtraData" +
               "     from TableWorkFlowAction where Id='" + WorkflowActionId + "'");

            
            string LinkParentId = WorkflowActionId;
            string RunningWorkflowTaskId = dtInfo.Rows[0]["RunningWorkflowTaskId"].ToString();

            bool blnCheckExitsRunningWorkflowTask = CheckExitsRunningWorkflowTask(oWsInParamCls, RunningWorkflowTaskId);
            if (!blnCheckExitsRunningWorkflowTask) RunningWorkflowTaskId = null;
            //string OldWorkflowHasSentId = null;
            //if (dtInfo.Rows[0]["frkWorkflowHasSentId"] != DBNull.Value)
            //{
            //    OldWorkflowHasSentId = dtInfo.Rows[0]["frkWorkflowHasSentId"].ToString();
            //}
            string GroupBatchId = dtInfo.Rows[0]["GroupBatchId"].ToString();
            string BatchId = dtInfo.Rows[0]["BatchId"].ToString();
            string ComeFromRoleId = dtInfo.Rows[0]["toRole"].ToString();//lay role hien thoi
            string RecordId = dtInfo.Rows[0]["RecordId"].ToString();
            string EmployeeLoginName = dtInfo.Rows[0]["EmployeeLoginName"].ToString();
            string EmployeeId = dtInfo.Rows[0]["EmployeeId"].ToString();
            string Owner = "";
            if (dtInfo.Rows[0]["Owner"] != DBNull.Value)
            {
                Owner = dtInfo.Rows[0]["Owner"].ToString();
            }
            string ExtraInfo = "";
            if (dtInfo.Rows[0]["ExtraInfo"] != DBNull.Value)
            {
                ExtraInfo = dtInfo.Rows[0]["ExtraInfo"].ToString();
            }

            string ExtraData = "";
            if (dtInfo.Rows[0]["ExtraData"] != DBNull.Value)
            {
                ExtraData = dtInfo.Rows[0]["ExtraData"].ToString();
            }

            string Subject = "";
            if (dtInfo.Rows[0]["Subject"] != DBNull.Value)
            {
                Subject = dtInfo.Rows[0]["Subject"].ToString();
            }

            string PreviewUrl = "";
            if (dtInfo.Rows[0]["PreviewUrl"] != DBNull.Value)
            {
                PreviewUrl = dtInfo.Rows[0]["PreviewUrl"].ToString();
            }
            string RecordNote = Note;
            string PrevLinkType = dtInfo.Rows[0]["LinkType"].ToString();
            string PreviewTarget = "_self";
            if (dtInfo.Rows[0]["PreviewTarget"] != DBNull.Value)
            {
                PreviewTarget = dtInfo.Rows[0]["PreviewTarget"].ToString();
            }
            string ComeFrom = dtInfo.Rows[0]["EmployeeId"].ToString();
            string ComeFromName = dtInfo.Rows[0]["EmployeeLoginName"].ToString();
            string ComeFromOfficeCode = dtInfo.Rows[0]["toOfficeCode"].ToString();
            string PriorityId = "";
            if (dtInfo.Rows[0]["PriorityId"] != DBNull.Value)
            {
                PriorityId = dtInfo.Rows[0]["PriorityId"].ToString();
            }
            string PriorityText = "";
            if (dtInfo.Rows[0]["PriorityText"] != DBNull.Value)
            {
                PriorityText = dtInfo.Rows[0]["PriorityText"].ToString();
            }
            string LinkBatchId = dtInfo.Rows[0]["LinkBatchId"].ToString();
            string OldStatus = "";
            if (dtInfo.Rows[0]["WorkflowStatus"] != DBNull.Value)
            {
                OldStatus = dtInfo.Rows[0]["WorkflowStatus"].ToString();
            }

            int WaitingTasks = int.Parse(dtInfo.Rows[0]["WaitingTasks"].ToString());
            int Sent = int.Parse(dtInfo.Rows[0]["Sent"].ToString());
            if (Sent == 1) throw new Exception("Đã chuyển không thực hiện chuyển nữa!");
            if (Sent == 2) throw new Exception("Đã chuyển bởi người khác có cùng cấp không thực hiện chuyển nữa!");
            if (WaitingTasks > 0) throw new Exception("Task đang trong trạng thái chờ task khác hoàn thành trước khi được chuyển!");

            string ReplyEmployeeId = ComeFrom;
            string ReplyEmployeeOfficeCode = ComeFromOfficeCode;



            bool Check = CheckPrevTaskDone(oWsInParamCls, WorkflowActionId);
            if (Check == false)
            {
                throw new Exception("Task trước có kiểu giải quyết song song. Các task này chưa hoàn thành nên không thể chuyển được!");
            }

            string XmlWorkflowData = GetXmlWorkflowData(oWsInParamCls, WorkflowActionId);
            WorkFlowApp wfa = CreateWorkFlowApp(XmlWorkflowData);

            string SendToUsers = "";
            string SendToUsersFullName = "";
            DataSet dsUser = new DataSet();
            dsUser.ReadXml(new StringReader(XmlUsers));
            EmployeeCls[] DedicateUsers = new EmployeeCls[0];
            if (dsUser.Tables.Count > 0)
            {
                DataTable dtUsers = dsUser.Tables[0];
                DedicateUsers = new EmployeeCls[dtUsers.Rows.Count];
                for (int iIndex = 0; iIndex < dtUsers.Rows.Count; iIndex++)
                {
                    string TempBatchId = "";
                    try
                    {
                        TempBatchId = (string)dtUsers.Rows[iIndex]["BatchId"];
                    }
                    catch { }

                    DedicateUsers[iIndex] = new EmployeeCls();
                    DedicateUsers[iIndex].EmployeeId = dtUsers.Rows[iIndex]["EmployeeId"].ToString();
                    DedicateUsers[iIndex].LoginName = dtUsers.Rows[iIndex]["LoginName"].ToString();
                    DedicateUsers[iIndex].FullName = dtUsers.Rows[iIndex]["FullName"].ToString();
                    string ItemRoleId = dtUsers.Rows[iIndex]["RoleId"].ToString();
                    string ItemRoleName = dtUsers.Rows[iIndex]["RoleName"].ToString();
                    DedicateUsers[iIndex].TempRoleId = new string[] { ItemRoleId };

                    DedicateUsers[iIndex].ToRole = new RoleCls();
                    DedicateUsers[iIndex].ToRole.RoleId = ItemRoleId;
                    DedicateUsers[iIndex].ToRole.RoleName = ItemRoleName;

                    DedicateUsers[iIndex].OfficeCode = dtUsers.Rows[iIndex]["OfficeCode"].ToString();
                    DedicateUsers[iIndex].BatchId = TempBatchId;
                    DedicateUsers[iIndex].ProcessType = dtUsers.Rows[iIndex]["ProcessType"].ToString();
                    if (String.IsNullOrEmpty(DedicateUsers[iIndex].BatchId))
                    {
                        DedicateUsers[iIndex].BatchId = BatchId;
                    }
                    SendToUsers = SendToUsers + DedicateUsers[iIndex].LoginName + ";";
                    //string RoleName = DedicateUsers[iIndex].r "";
                    //RoleCls r = wfa.FindRole(ItemRoleId);
                    //if (r != null)
                    //{
                    //    RoleName = r.RoleName;
                    //}
                    SendToUsersFullName = SendToUsersFullName + DedicateUsers[iIndex].FullName;
                    if (!string.IsNullOrEmpty(ItemRoleName))
                    {
                        SendToUsersFullName += "-" + ItemRoleName;
                    }
                    SendToUsersFullName += ";";
                }
            }
            int iFound = SendToUsers.IndexOf(";;");
            while (iFound != -1)
            {
                SendToUsers = SendToUsers.Replace(";;", ";");
                iFound = SendToUsers.IndexOf(";;");
            }
            SendToUsers = SendToUsers.Replace(";", "; ");
            if (string.IsNullOrEmpty(SendToUsers))
            {
                SendToUsers = EmployeeLoginName;
            }


            string WorkFlowDefId = wfa.WorkFlowDefCls.WorkFlowDefId;
            LinkCls oLinkCls = GetLink(wfa, LinkId);
            if (oLinkCls == null) throw new Exception("LinkId [" + LinkId + "] not found!");
            DateTime ExpireDate = System.DateTime.Now.AddDays(oLinkCls.ProcessDays);
            int IsReply = 0;
            if (oLinkCls.ForAllEmployeeInRole == 0)
            {
                EmployeeCls FoundEmployee = DetectFromEmployee(oWsInParamCls, wfa, WorkflowActionId, oLinkCls.ReturnLinkId);
                if (FoundEmployee == null) throw new Exception("Parent not found!");
                DedicateUsers = new EmployeeCls[] { FoundEmployee };
                SendToUsers = FoundEmployee.LoginName;
                IsReply = 1;
            }

            string NextStatus = oLinkCls.NextViewParam;// OldStatus;
            if (String.IsNullOrEmpty(NextStatus)) NextStatus = OldStatus;


            WaitingTasks = DedicateUsers.Length;
            if (oLinkCls.WaitType.Equals("Not waiting"))
            {
                WaitingTasks = 0;
            }
            if (String.IsNullOrEmpty(oLinkCls.WaitType)) WaitingTasks = 0;
            if (ProcessDays.Equals("0"))
            {
                ProcessDays = oLinkCls.ProcessDays.ToString();
            }
            int DeleteBeforeNext = wfa.WorkFlowDefCls.DeleteBeforeNext;
            string ParentWaitingTasksId = null;
            if (LinkParentId != null)
            {
                ParentWaitingTasksId = GetParentId(oWsInParamCls, LinkParentId);
            }
            ProcessCls NextProcess = GetProcess(oWsInParamCls, wfa, oLinkCls.toNodeId);

            bool hasBeginTrans = dbTransaction != null;
            if (dbTransaction == null)
            {
                dbTransaction = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).BeginTransaction();
            }
            try
            {
                string DllPath = oSiteParam.DllPath;

                //DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                //        dbTransaction,
                //        " Delete from TableWorkflowCurrentProcess where RecordId=@RecordId; " +
                //        " Insert into TableWorkflowCurrentProcess(RecordId,ObjectType,CurrentProcess,CurrentProcessFullName) values (@RecordId,@ObjectType,@CurrentProcess,@CurrentProcessFullName)",
                //        new Model.DatabaseParamCls[]{
                //                new Model.DatabaseParamCls("RecordId",RecordId),
                //                new Model.DatabaseParamCls("ObjectType",ExtraInfo),
                //                new Model.DatabaseParamCls("CurrentProcess",SendToUsers),
                //                new Model.DatabaseParamCls("CurrentProcessFullName",SendToUsersFullName),
                //        }, CommandType.Text);



                ////xoa quyen sua va quyen xoa
                //DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                //        dbTransaction,
                //           " Delete from TableWorkflowPermissionGrant where ObjectId=@ObjectId and PermissionType='update'; ",
                //           new Model.DatabaseParamCls[]{
                //                    new Model.DatabaseParamCls("ObjectId",RecordId),
                //                    new Model.DatabaseParamCls("PermissionType","update"),
                //            }, CommandType.Text);

                //DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                //         dbTransaction,
                //            " Delete from TableWorkflowPermissionGrant where ObjectId=@ObjectId and PermissionType='update'; ",
                //            new Model.DatabaseParamCls[]{
                //                    new Model.DatabaseParamCls("ObjectId",RecordId),
                //                    new Model.DatabaseParamCls("PermissionType","delete"),
                //            }, CommandType.Text);


                //if (string.IsNullOrEmpty(BatchId) == false)
                //{
                //    //doan nay cap nhat vao toan bo cac thang WorkflowReceived de bao la da xy ly
                //    string UpdateReceiveText = "Update TableWorkflowHasReceived set HasProcessed=1, ProcessedDate=GetDate() where frkBatchId=@frkBatchId";
                //    DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                //         dbTransaction,
                //         UpdateReceiveText,
                //         new Model.DatabaseParamCls[]{
                //                    new Model.DatabaseParamCls("frkBatchId",BatchId),
                //            }, CommandType.Text);
                //}


                //string SentCommandText = "Insert into [TableWorkflowHasSent]([WorkflowHasSentId],[Subject], [Description], [frkWorkflowDefId], [SentDate], [SendToUsers], [EntryBy], [Comment], [IsProcessed], [RecordId], [ObjectType], [OwnerRoleId]) values (@WorkflowHasSentId,@Subject, @Description, @frkWorkflowDefId, GetDate(), @SendToUsers, @EntryBy, @Comment, 0, @RecordId, @ObjectType, @OwnerRoleId)";
                ////doan nay nhet vao sentto
                //DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                //      dbTransaction,
                //      SentCommandText,
                //      new Model.DatabaseParamCls[]{
                //                    new Model.DatabaseParamCls("WorkflowHasSentId",WorkflowHasSentId),
                //                    new Model.DatabaseParamCls("Subject",Subject),
                //                    new Model.DatabaseParamCls("Description",RecordNote),
                //                    new Model.DatabaseParamCls("frkWorkflowDefId",WorkFlowDefId),
                //                    new Model.DatabaseParamCls("SendToUsers",SendToUsers),
                //                    new Model.DatabaseParamCls("EntryBy",WebSessionUtility.GetCurrentLoginUser().LoginName),
                //                    new Model.DatabaseParamCls("Comment",Note),
                //                    new Model.DatabaseParamCls("RecordId",RecordId),
                //                    new Model.DatabaseParamCls("ObjectType",ExtraInfo),
                //                    new Model.DatabaseParamCls("OwnerRoleId",ComeFromRoleId),
                //            }, CommandType.Text);

                //if (string.IsNullOrEmpty(OldWorkflowHasSentId) == false)
                //{
                //    string UpdateSentTaskCommandText = "Update TableWorkflowHasSent set IsProcessed=1, ProcessedBy=@ProcessedBy,ProcessedDate=GetDate(),ProcessedComment=@ProcessedComment where WorkflowHasSentId=@WorkflowHasSentId";
                //    DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                //        dbTransaction,
                //        UpdateSentTaskCommandText,
                //        new Model.DatabaseParamCls[]{
                //                    new Model.DatabaseParamCls("ProcessedBy",WebSessionUtility.GetCurrentLoginUser().LoginName),
                //                    new Model.DatabaseParamCls("ProcessedComment",Note),
                //                    new Model.DatabaseParamCls("WorkflowHasSentId",OldWorkflowHasSentId),
                //            }, CommandType.Text);
                //}
                //string ActionUrl=null;
                //doan nay chay wf...!
                //đoạn này cần kiểm tra nếu chạy parallel thì chạy lần đầu tiên thôi
                if (string.IsNullOrEmpty(RunWorkflowFunction) == false)
                {
                    DataSet dsRunFunctions = new DataSet();
                    dsRunFunctions.ReadXml(new StringReader(RunWorkflowFunction));
                    if (dsRunFunctions.Tables.Count > 0)
                    {
                        Collection<ProcessWorkflowFunctionParamCls> ProcessWorkflowFunctionParams = new Collection<ProcessWorkflowFunctionParamCls> { };
                        for (int iIndex = 0; iIndex < dsRunFunctions.Tables[0].Rows.Count; iIndex++)
                        {
                            string ItemRunCommandText = dsRunFunctions.Tables[0].Rows[iIndex]["RunCommandText"].ToString();
                            string ItemXmlData = dsRunFunctions.Tables[0].Rows[iIndex]["XmlData"].ToString();
                            string ItemRecordId = dsRunFunctions.Tables[0].Rows[iIndex]["RecordId"].ToString();
                            string ItemWorkflowActionId = dsRunFunctions.Tables[0].Rows[iIndex]["WorkflowActionId"].ToString();
                            string ItemWorkflowDefId = dsRunFunctions.Tables[0].Rows[iIndex]["WorkflowDefId"].ToString();
                            string WorkflowFunctionId = dsRunFunctions.Tables[0].Rows[iIndex]["WorkflowFunctionId"].ToString();

                            bool RunAtServer = false;
                            try
                            {
                                RunAtServer = bool.Parse(dsRunFunctions.Tables[0].Rows[iIndex]["RunAtServer"].ToString());
                            }
                            catch { }
                            if (RunAtServer == false)
                            {
                                ProcessWorkflowFunctionParamCls oProcessWorkflowFunctionParamCls = new ProcessWorkflowFunctionParamCls();
                                oProcessWorkflowFunctionParamCls.dbTransaction = dbTransaction;
                                oProcessWorkflowFunctionParamCls.RunCommandText = ItemRunCommandText;
                                oProcessWorkflowFunctionParamCls.XmlData = ItemXmlData;
                                oProcessWorkflowFunctionParamCls.RecordId = ItemRecordId;
                                oProcessWorkflowFunctionParamCls.WorkflowActionId = ItemWorkflowActionId;
                                oProcessWorkflowFunctionParamCls.WorkflowDefId = ItemWorkflowDefId;
                                oProcessWorkflowFunctionParamCls.oWsInParamCls = oWsInParamCls;

                                ProcessWorkflowFunctionParams.Add(oProcessWorkflowFunctionParamCls);
                            }
                            else
                            {
                                IWfFunction
                                    WfFunction = WorkFlowFunctionMan.Find(DllPath, WorkflowFunctionId);
                                WfExecuteParamCls oWfExecuteParamCls = new WfExecuteParamCls();
                                oWfExecuteParamCls.RecordId = RecordId;
                                oWfExecuteParamCls.WorkflowActionId = ItemWorkflowActionId;
                                oWfExecuteParamCls.WorkflowDefId = ItemWorkflowDefId;
                                oWfExecuteParamCls.SiteId = SiteId;
                                oWfExecuteParamCls.ObjectType = ExtraInfo;
                                oWfExecuteParamCls.ObjectCreatedBy = Owner;
                                oWfExecuteParamCls.DedicateUsers = DedicateUsers;
                                oWfExecuteParamCls.ResponsibleId = ResponsibleId;
                                oWfExecuteParamCls.Responsible = Responsible;
                                oWfExecuteParamCls.JoinerId = JoinerId;
                                oWfExecuteParamCls.Joiner = Joiner;
                                try
                                {
                                    oWfExecuteParamCls.ToUser = SendToUsers.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); ;
                                }
                                catch { }
                                if (WfFunction != null)
                                {
                                    oWfExecuteParamCls.SqlTransaction = dbTransaction;
                                    RetWfExecuteParamCls oRetWfExecuteParamCls = WfFunction.Execute(oWfExecuteParamCls);
                                    if (oRetWfExecuteParamCls.ReturnIsLink)
                                    {
                                        oDoNextLinkRunAtServerReturnCls.IsLink = true;
                                        oDoNextLinkRunAtServerReturnCls.Url = oRetWfExecuteParamCls.Url;
                                    }
                                }
                            }
                        }
                        IProcessWorkflowFunction[]
                            ProcessWorkflowFunctions = ProcessWorkflowFunctionMan.LoadWfFunctions(DllPath);
                        for (int iIndexParam = 0; iIndexParam < ProcessWorkflowFunctionParams.Count; iIndexParam++)
                        {
                            for (int iIndexFunction = 0; iIndexFunction < ProcessWorkflowFunctions.Length; iIndexFunction++)
                            {
                                ReturnProcessWorkflowFunctionParamCls oReturnProcessWorkflowFunctionParamCls = ProcessWorkflowFunctions[iIndexFunction].Execute(ProcessWorkflowFunctionParams[iIndexParam]);
                                if (oReturnProcessWorkflowFunctionParamCls.Error)
                                {
                                    throw new Exception(oReturnProcessWorkflowFunctionParamCls.ReturnMsg);
                                }
                                //if (oReturnProcessWorkflowFunctionParamCls.ProcessOk)
                                //{
                                //    break;
                                //}
                            }
                        }
                    }
                }

                if (DedicateUsers.Length == 0)
                {
                    if (oLinkCls.FinishThisTask != 0)
                    {
                        EmployeeCls FoundEmployeeCls = CreateEmployeeModelFromUser(SiteId, EmployeeId);
                        DedicateUsers = new EmployeeCls[]{
                            FoundEmployeeCls
                        };
                    }
                }


                //DataTable dtUserOwner = null;
                if (DedicateUsers.Length > 0)
                {
                    #region old
                    //    if (oLinkCls.ShowOwner)
                    //    {
                    //        string DeleteText =
                    //                   " Delete from TableDocumentOwner where frkDocumentId=@DocumentId";
                    //        DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                    //             dbTransaction,
                    //             DeleteText,
                    //             new Model.DatabaseParamCls[]{
                    //                        new Model.DatabaseParamCls("DocumentId",RecordId),
                    //                    }, CommandType.Text);

                    //        string LoginNameText = "(";
                    //        for (int iIndex = 0; iIndex < DedicateUsers.Length; iIndex++)
                    //        {
                    //            LoginNameText += "'" + DedicateUsers[iIndex].EmployeeId + "'";
                    //            if (iIndex < DedicateUsers.Length - 1)
                    //            {
                    //                LoginNameText += ",";
                    //            }
                    //        }
                    //        LoginNameText += ")";

                    //        //doan nay kiem tra xem co phai ghi vao chu tri va phoi hop khong...!
                    //        string commandText =
                    //            " select UserId,DepartmentId,OfficeId from TableUser" +
                    //            "   left outer join TableDepartment on TableDepartment.DepartmentId=fk_Department_Id" +
                    //            "   left outer join TableOffice on TableOffice.OfficeId=TableDepartment.fk_Office_Id" +
                    //            " where UserId in " + LoginNameText;
                    //        dtUserOwner = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(commandText);
                    //        for (int iIndex = 0; iIndex < DedicateUsers.Length; iIndex++)
                    //        {
                    //            DataView dv = new DataView(dtUserOwner, "UserId='" + DedicateUsers[iIndex].EmployeeId + "'", "", DataViewRowState.CurrentRows);
                    //            if (dv.Count > 0)
                    //            {
                    //                string OfficeId = null;
                    //                if (dv[0]["OfficeId"] != DBNull.Value)
                    //                {
                    //                    OfficeId = (string)dv[0]["OfficeId"];
                    //                }
                    //                string DepartmentId = null;
                    //                if (dv[0]["DepartmentId"] != DBNull.Value)
                    //                {
                    //                    DepartmentId = (string)dv[0]["DepartmentId"];
                    //                }
                    //                string InsertText = 
                    //                    " Insert into TableDocumentOwner(DocumentOwnerId, frkDocumentId, LevelOfficeId, LevelDepartmentId, LevelUserId, IsMainProcess) values (@DocumentOwnerId, @DocumentId, @LevelOfficeId, @LevelDepartmentId, @LevelUserId, @IsMainProcess)";
                    //                DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                    //                     dbTransaction,
                    //                     InsertText,
                    //                     new Model.DatabaseParamCls[]{
                    //                        new Model.DatabaseParamCls("DocumentOwnerId",System.Guid.NewGuid().ToString()),
                    //                        new Model.DatabaseParamCls("DocumentId",RecordId),
                    //                        new Model.DatabaseParamCls("LevelOfficeId",OfficeId),
                    //                        new Model.DatabaseParamCls("LevelDepartmentId",DepartmentId),
                    //                        new Model.DatabaseParamCls("LevelUserId",DedicateUsers[iIndex].EmployeeId),
                    //                        new Model.DatabaseParamCls("IsMainProcess",DedicateUsers[iIndex].ProcessType.ToLower().Equals("to")?1:0),
                    //                    }, CommandType.Text);
                    //            }
                    //        }
                    //    }
                    #endregion
                    if (WaitingTasks == 1)
                    {
                        string CommandText = "Update TableWorkflowAction set WaitingTasks=@WaitingTasks where Id=@Id";
                        DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                                dbTransaction,
                                CommandText,
                                new Model.DatabaseParamCls[]{
                                new Model.DatabaseParamCls("Id",LinkParentId),
                                new Model.DatabaseParamCls("WaitingTasks",DbType.Int32, WaitingTasks),
                            }, CommandType.Text);
                        //cho nay neu =1 thi dat cai task hien thoi la cho...!
                        WaitingTasks = 0;//dat = 0 rat quan trong vi de tao cho cac sub - task luon = 0
                    }

                    //doan nay tu dong dat nhung chu lien quan ve het sau khi xu ly
                    if (PrevLinkType.Equals("Sequence"))
                    {
                        string CommandTextA = " Update TableWorkflowAction set Sent=2 where LinkBatchId=@LinkBatchId";
                        DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                            dbTransaction,
                            CommandTextA,
                            new Model.DatabaseParamCls[]{
                            new Model.DatabaseParamCls("LinkBatchId",LinkBatchId)
                        }, CommandType.Text);
                    }

                    //ArrayList ArrayListAttachFiles = new ArrayList();
                    ////doan nay nhet vao trong thang cho danh sach cac file attached...!
                    //if (string.IsNullOrEmpty(AttachFileSessionId) == false)
                    //{
                    //    //doan nay gan attach file
                    //    string PathRoot = oSiteParam.PathRoot;
                    //    string PathFile = PathRoot + "\\media\\" + oSiteParam.SiteId + "\\TempUploadFiles\\" + AttachFileSessionId;
                    //    string[] Files = System.IO.Directory.GetFiles(PathFile);

                    //    //ConvertToFlash.ConvertToFlashItem[] ConvertToFlashItems = new ConvertToFlash.ConvertToFlashItem[Files.Length];
                    //    for (int iIndex = 0; iIndex < Files.Length; iIndex++)
                    //    {
                    //        string WorkflowAttachFileId = System.Guid.NewGuid().ToString();

                    //        string SaveFile = WorkflowAttachFileId + new System.IO.FileInfo(Files[iIndex]).Extension;
                    //        string SaveFileXml = WorkflowAttachFileId + ".xml";
                    //        byte[] Bytes = FunctionUtilities.GetBytesFromFile(Files[iIndex]);

                    //        //ConvertToFlashItems[iIndex] = new ConvertToFlash.ConvertToFlashItem();
                    //        //ConvertToFlashItems[iIndex].ObjectId = WorkflowAttachFileId;
                    //        //ConvertToFlashItems[iIndex].ObjectType = "WorkflowAttachFile";
                    //        //ConvertToFlashItems[iIndex].SourceFileName = Files[iIndex];
                    //        //ConvertToFlashItems[iIndex].TableName = "TableWorkflowAttachFile";
                    //        //ConvertToFlashItems[iIndex].FieldName = "FlashContent";
                    //        //ConvertToFlashItems[iIndex].FieldKey = "WorkflowAttachFileId";


                    //        string CommandText = "Insert into TableWorkflowAttachFile(WorkflowAttachFileId, frkRunningWorkflowTaskId, WorkflowDefId, AttachFileName, Ext, Body, SaveFolder, SaveFile, SaveFileXml, AttachedDate, AttachedBy) values (@WorkflowAttachFileId, @frkRunningWorkflowTaskId, @WorkflowDefId, @AttachFileName, @Ext, @Body, @SaveFolder, @SaveFile, @SaveFileXml, GetDate(), @AttachedBy)";
                    //        DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                    //              dbTransaction,
                    //              CommandText,
                    //              new Model.DatabaseParamCls[]{
                    //                new Model.DatabaseParamCls("WorkflowAttachFileId",WorkflowAttachFileId),
                    //                new Model.DatabaseParamCls("frkRunningWorkflowTaskId",RunningWorkflowTaskId),
                    //                new Model.DatabaseParamCls("WorkflowDefId",WorkFlowDefId),
                    //                new Model.DatabaseParamCls("AttachFileName",new System.IO.FileInfo(Files[iIndex]).Name),
                    //                new Model.DatabaseParamCls("Ext",new System.IO.FileInfo(Files[iIndex]).Extension),
                    //                new Model.DatabaseParamCls("Body",DbType.Binary, Bytes),
                    //                new Model.DatabaseParamCls("SaveFolder",null),
                    //                new Model.DatabaseParamCls("SaveFile",SaveFile),
                    //                new Model.DatabaseParamCls("SaveFileXml",SaveFileXml),
                    //                new Model.DatabaseParamCls("AttachedBy",WebSessionUtility.GetCurrentLoginUser().LoginName),
                    //        }, CommandType.Text);


                    //        TempAttachFile oTempAttachFile = new TempAttachFile();
                    //        oTempAttachFile.WorkflowAttachFileId = WorkflowAttachFileId;
                    //        oTempAttachFile.RealFile = new System.IO.FileInfo(Files[iIndex]).Name;
                    //        //oTempAttachFile.Data = Bytes;
                    //        oTempAttachFile.AttachedBy = WebSessionUtility.GetCurrentLoginUser().LoginName;
                    //        oTempAttachFile.AttachedDate = System.DateTime.Now;
                    //        ArrayListAttachFiles.Add(oTempAttachFile);
                    //        //new object[]{ WorkflowAttachFileId,Bytes});
                    //    }
                    //    //ConvertToFlash.ConvertToFlashDll.AddToQueue((SqlTransaction)dbTransaction, FlashQueuePath, ConvertToFlashItems);
                    //}



                    ProcessCls CurrentProcess = GetProcess(oWsInParamCls, wfa, oLinkCls.fromNodeId);
                    if (NextProcess == null) throw new Exception("Next Process from Start Point not found!");
                    LinkBatchId = System.Guid.NewGuid().ToString().Substring(0, 8);
                    string ItemBatchId = BatchId;

                    string FirstWorkflowActionId = null;
                    //doan nay kiem tra xem co phai chuyen sub-workflow khong...!
                    for (int iIndexUser = 0; iIndexUser < DedicateUsers.Length; iIndexUser++)
                    {
                        RoleCls ActiveRoleCls = new RoleCls();
                        ActiveRoleCls.RoleId = WebSessionUtility.GetCurrentLoginUser().RoleModel.RoleId;// GetRole(oWsInParamCls, wfa, ComeFromRoleId);
                        ActiveRoleCls.RoleName = WebSessionUtility.GetCurrentLoginUser().RoleModel.RoleName;
                        if (String.IsNullOrEmpty(DedicateUsers[iIndexUser].BatchId) == false)
                        {
                            ItemBatchId = DedicateUsers[iIndexUser].BatchId;
                        }

                        string ItemWorkflowActionId = System.Guid.NewGuid().ToString();
                        if (FirstWorkflowActionId == null) FirstWorkflowActionId = ItemWorkflowActionId;
                        InsertIntoDatabase(
                            oWsInParamCls,
                            dbTransaction,
                            wfa,
                            ActiveRoleCls,
                            oLinkCls,
                            RunningWorkflowTaskId,
                            ItemWorkflowActionId,
                            GroupBatchId,
                            ItemBatchId,
                            LinkBatchId,
                            RecordId,
                            NextProcess.ProcessId,
                            ComeFromRoleId,
                            ActiveRoleCls.RoleName,
                            ComeFrom,
                            ComeFromName,
                            ComeFromOfficeCode,
                            ReplyEmployeeId,
                            ReplyEmployeeOfficeCode,
                            Subject,
                            RecordNote,
                            PreviewUrl,
                            PreviewTarget,
                            "",
                            LinkId,
                            XmlData,
                            CurrentProcess,
                            NextProcess,
                            oLinkCls.NextViewParam,
                            ComeFromOfficeCode,
                            DedicateUsers[iIndexUser],
                            DedicateUsers[iIndexUser].ToRole,
                            DeleteBeforeNext,
                            LinkParentId,
                            DedicateUsers[iIndexUser].ProcessType,
                            WaitingTasks,
                            int.Parse(ProcessDays),
                            PriorityId,
                            PriorityText,
                            ExpireDate,
                            oLinkCls.LinkType,
                            oLinkCls.ReturnLinkId,
                            ComeFromName,
                            ExtraInfo,
                            ExtraData,
                            0,
                            "",
                            IsReply);

                        //shared tai lieu cho thang nay
                        //AddShareObjectToUser((SqlTransaction)dbTransaction, SiteId, ExtraInfo, RecordId, DedicateUsers[iIndexUser].LoginName, DedicateUsers[iIndexUser].FullName);

                        //for (int iAttachFile = 0; iAttachFile < ArrayListAttachFiles.Count; iAttachFile++)
                        //{
                        //    TempAttachFile oTempAttachFile = (TempAttachFile)ArrayListAttachFiles[iAttachFile];
                        //    string WorkflowAttachFileId = oTempAttachFile.WorkflowAttachFileId;
                        //    //byte[] b = oTempAttachFile.Data;
                        //    //doan nay nhet vao bang TableWorkflowActionAttachedFile
                        //    string CommandText = "Insert into TableWorkflowActionAttachFile(WorkflowActionAttachFileId, frkWorkflowAttachFileId, frkWorkflowActionId, WorkflowDefId) values (@WorkflowActionAttachFileId, @frkWorkflowAttachFileId, @frkWorkflowActionId, @WorkflowDefId)";
                        //    DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                        //          dbTransaction,
                        //          CommandText,
                        //          new Model.DatabaseParamCls[]{
                        //            new Model.DatabaseParamCls("WorkflowActionAttachFileId",System.Guid.NewGuid().ToString()),
                        //            new Model.DatabaseParamCls("frkWorkflowAttachFileId",WorkflowAttachFileId),
                        //            new Model.DatabaseParamCls("frkWorkflowActionId",ItemWorkflowActionId),
                        //            new Model.DatabaseParamCls("WorkflowDefId",WorkFlowDefId),
                        //    }, CommandType.Text);
                        //}
                        //doan nay nhet attached cu
                        //for (int iOldAttachFile = 0; iOldAttachFile < AllAttachedDocumentIds.Length; iOldAttachFile++)
                        //{
                        //    string OldAttachedItemId = AllAttachedDocumentIds[iOldAttachFile].Trim();
                        //    string CommandText = "Insert into TableWorkflowActionAttachFile(WorkflowActionAttachFileId, frkWorkflowAttachFileId, frkWorkflowActionId, WorkflowDefId) values (@WorkflowActionAttachFileId, @frkWorkflowAttachFileId, @frkWorkflowActionId, @WorkflowDefId)";
                        //    DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                        //          dbTransaction,
                        //          CommandText,
                        //          new Model.DatabaseParamCls[]{
                        //            new Model.DatabaseParamCls("WorkflowActionAttachFileId",System.Guid.NewGuid().ToString()),
                        //            new Model.DatabaseParamCls("frkWorkflowAttachFileId",OldAttachedItemId),
                        //            new Model.DatabaseParamCls("frkWorkflowActionId",ItemWorkflowActionId),
                        //            new Model.DatabaseParamCls("WorkflowDefId",WorkFlowDefId),
                        //    }, CommandType.Text);
                        //}



                        //string WorkflowHasReceivedId = System.Guid.NewGuid().ToString();
                        //int iProcessDays = 2;
                        //try
                        //{
                        //    iProcessDays = int.Parse(ProcessDays);
                        //}
                        //catch
                        //{
                        //}
                        
                        ////doan nay nhet vao task cua thang nao nhan
                        //string ReceivedCommandText = "Insert into [TableWorkflowHasReceived]([WorkflowHasReceivedId],[Subject], [Description], [frkWorkflowDefId], [ReceivedDate], [SendFromUser], [SendFromLoginName], [Owner], [Comment], [HasProcessed], [RecordId], [ObjectType], [frkWorkflowActionId], [frkBatchId], [DueDate], [OwnerRoleId]) values (@WorkflowHasReceivedId,@Subject, @Description, @frkWorkflowDefId, GetDate(), @SendFromUser,@SendFromLoginName, @Owner, @Comment, 0, @RecordId, @ObjectType, @frkWorkflowActionId, @frkBatchId,@DueDate, @OwnerRoleId)";
                        ////doan nay nhet vao Receivedto
                        //DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                        //      dbTransaction,
                        //      ReceivedCommandText,
                        //      new Model.DatabaseParamCls[]{
                        //            new Model.DatabaseParamCls("WorkflowHasReceivedId",WorkflowHasReceivedId),
                        //            new Model.DatabaseParamCls("Subject",Subject),
                        //            new Model.DatabaseParamCls("Description",RecordNote),
                        //            new Model.DatabaseParamCls("frkWorkflowDefId",WorkFlowDefId),
                        //            new Model.DatabaseParamCls("SendFromUser",ComeFrom),
                        //            new Model.DatabaseParamCls("SendFromLoginName",ComeFromName),
                        //            new Model.DatabaseParamCls("Owner",DedicateUsers[iIndexUser].LoginName),
                        //            new Model.DatabaseParamCls("Comment",Note),
                        //            new Model.DatabaseParamCls("RecordId",RecordId),
                        //            new Model.DatabaseParamCls("ObjectType",ExtraInfo),
                        //            new Model.DatabaseParamCls("frkWorkflowActionId",ItemWorkflowActionId),
                        //            new Model.DatabaseParamCls("frkBatchId",ItemBatchId),
                        //            new Model.DatabaseParamCls("DueDate",System.DateTime.Now.AddDays(iProcessDays)),
                        //            new Model.DatabaseParamCls("OwnerRoleId",DedicateUsers[iIndexUser].TempRoleId[0]),
                        //    }, CommandType.Text);
                    }




                    //nhet vao lich su

                    ////doan nay nhet vao lich su van chuyen....!
                    //string SendToUsersText = SendToUsers.Replace(";", "; ");
                    //string DocumentNextHistoryId = System.Guid.NewGuid().ToString();
                    //string InsertHistoryCommand =
                    //    " Insert into TableDocumentNextHistory(DocumentNextHistoryId, ActionDate,ProcessUser, ProcessUserName, ProcessNote, ObjectType, ObjectId, HistorySendToUsers, CurrentWfStatus, WorkflowProcessText, WorkflowNextLinkName) values (@DocumentNextHistoryId, @ActionDate,@ProcessUser, @ProcessUserName, @ProcessNote, @ObjectType, @ObjectId, @HistorySendToUsers, @CurrentWfStatus, @WorkflowProcessText,@WorkflowNextLinkName); ";
                    //if (FirstWorkflowActionId != null)
                    //{
                    //    InsertHistoryCommand +=
                    //    " Insert into [TableDocumentNextHistoryAttachFile](DocumentNextHistoryAttachFileId, frkDocumentNextHistoryId, ContentFile, FlashContent, RealFile, AttachedDate, AttachedBy, frkWorkflowAttachFileId)" +
                    //    "   (" +
                    //    "       select newid(),@DocumentNextHistoryId,Body,FlashContent, AttachFileName, AttachedDate, AttachedBy,WorkflowAttachFileId from TableWorkflowActionAttachFile" +
                    //    "           join TableWorkflowAttachFile on TableWorkflowAttachFile.WorkflowAttachFileId=frkWorkflowAttachFileId" +
                    //    "       where frkWorkflowActionId=@WorkflowActionId" +
                    //    "   )";
                    //}

                    string NextStatusText = wfa.FindStatusText(NextStatus);
                    string WorkflowProcessText = NextProcess.ProcessName;
                    string WorkflowNextLinkName = oLinkCls.LinkName;
                    //DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                    //         dbTransaction,
                    //         InsertHistoryCommand,
                    //         new Model.DatabaseParamCls[]{
                    //                new Model.DatabaseParamCls("DocumentNextHistoryId",DocumentNextHistoryId),
                    //                new Model.DatabaseParamCls("ActionDate",System.DateTime.Now),
                    //                new Model.DatabaseParamCls("ProcessUser",ComeFrom),
                    //                new Model.DatabaseParamCls("ProcessUserName",ComeFromName),
                    //                new Model.DatabaseParamCls("ProcessNote",Note),
                    //                new Model.DatabaseParamCls("ObjectType",ExtraInfo),
                    //                new Model.DatabaseParamCls("ObjectId",RecordId),
                    //                new Model.DatabaseParamCls("SendToUsers",SendToUsers),
                    //                new Model.DatabaseParamCls("HistorySendToUsers",SendToUsersText),
                    //                new Model.DatabaseParamCls("WorkflowActionId",FirstWorkflowActionId),
                    //                new Model.DatabaseParamCls("CurrentWfStatus",NextStatusText),
                    //                new Model.DatabaseParamCls("WorkflowProcessText",WorkflowProcessText),
                    //                new Model.DatabaseParamCls("WorkflowNextLinkName",WorkflowNextLinkName),
                    //        }, CommandType.Text);


                    //quan nay update vao trang thai xu ly
                    string ProcessBy = "";
                    for (int iIndex = 0; iIndex < DedicateUsers.Length; iIndex++)
                    {
                        ProcessBy = ProcessBy + DedicateUsers[iIndex].LoginName;
                        if (iIndex > 4)
                        {
                            ProcessBy = ProcessBy + "<br>... (<a href=\"#\">toàn bộ</a>)";
                        }
                        if (iIndex < DedicateUsers.Length)
                        {
                            ProcessBy = ProcessBy + "<br>";
                        }
                    }
                    string RunCommandTextFinishTask = "Update TableRunningWorkflowTask set ProcessBy=@ProcessBy,WorkingStatus=N'Đang xử lý',ProcessAt=@ProcessAt,CurrentDate=@CurrentDate,DaysForProcess=@DaysForProcess where ObjectRecordId=@ObjectRecordId";
                    DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                        dbTransaction,
                        RunCommandTextFinishTask,
                        new Model.DatabaseParamCls[]{
                                    new Model.DatabaseParamCls("ProcessBy",ProcessBy),
                                    new Model.DatabaseParamCls("ProcessAt",NextProcess.ProcessName),
                                    new Model.DatabaseParamCls("CurrentDate",System.DateTime.Now),
                                    new Model.DatabaseParamCls("DaysForProcess",ProcessDays),
                                    new Model.DatabaseParamCls("ObjectRecordId",RecordId),
                            }, CommandType.Text);
                }
                else
                {
                    //string SendToUsersText = SendToUsers.Replace(";", "; ");
                    //string DocumentNextHistoryId = System.Guid.NewGuid().ToString();
                    //string InsertHistoryCommand =
                    //    " Insert into TableDocumentNextHistory(DocumentNextHistoryId, ActionDate,ProcessUser, ProcessUserName, ProcessNote, ObjectType, ObjectId, HistorySendToUsers, CurrentWfStatus, WorkflowProcessText, WorkflowNextLinkName) values (@DocumentNextHistoryId, @ActionDate,@ProcessUser, @ProcessUserName, @ProcessNote, @ObjectType, @ObjectId, @HistorySendToUsers, @CurrentWfStatus, @WorkflowProcessText,@WorkflowNextLinkName); " +
                    //    " Insert into [TableDocumentNextHistoryAttachFile](DocumentNextHistoryAttachFileId, frkDocumentNextHistoryId, ContentFile, FlashContent, RealFile, AttachedDate, AttachedBy)" +
                    //    "   (" +
                    //    "       select newid(),@DocumentNextHistoryId,Body,FlashContent, AttachFileName, AttachedDate, AttachedBy from TableWorkflowActionAttachFile" +
                    //    "           join TableWorkflowAttachFile on TableWorkflowAttachFile.WorkflowAttachFileId=frkWorkflowAttachFileId" +
                    //    "       where frkWorkflowActionId=@WorkflowActionId" +
                    //    "   )";


                    string NextStatusText = wfa.FindStatusText(NextStatus);
                    string WorkflowProcessText = NextProcess.ProcessName;
                    string WorkflowNextLinkName = oLinkCls.LinkName;
                    //DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                    //         dbTransaction,
                    //         InsertHistoryCommand,
                    //         new Model.DatabaseParamCls[]{
                    //                new Model.DatabaseParamCls("DocumentNextHistoryId",DocumentNextHistoryId),
                    //                new Model.DatabaseParamCls("ActionDate",System.DateTime.Now),
                    //                new Model.DatabaseParamCls("ProcessUser",ComeFrom),
                    //                new Model.DatabaseParamCls("ProcessUserName",ComeFromName),
                    //                new Model.DatabaseParamCls("ProcessNote",Note),
                    //                new Model.DatabaseParamCls("ObjectType",ExtraInfo),
                    //                new Model.DatabaseParamCls("ObjectId",RecordId),
                    //                new Model.DatabaseParamCls("SendToUsers",SendToUsers),
                    //                new Model.DatabaseParamCls("HistorySendToUsers",SendToUsersText),
                    //                new Model.DatabaseParamCls("WorkflowActionId",WorkflowActionId),
                    //                new Model.DatabaseParamCls("CurrentWfStatus",NextStatusText),
                    //                new Model.DatabaseParamCls("WorkflowProcessText",WorkflowProcessText),
                    //                new Model.DatabaseParamCls("WorkflowNextLinkName",WorkflowNextLinkName),
                    //        }, CommandType.Text);



                    //update status only...!
                    if (NextStatus.Equals(OldStatus) == false)
                    {
                        string CommandText = "Update TableWorkflowAction set ViewParam=@WorkflowStatus, WorkflowStatus=@WorkflowStatus where Id=@Id";
                        DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                            dbTransaction,
                            CommandText,
                            new Model.DatabaseParamCls[]{
                                    new Model.DatabaseParamCls("Id",WorkflowActionId),
                                    new Model.DatabaseParamCls("WorkflowStatus",NextStatus),
                                    new Model.DatabaseParamCls("ViewParam",NextStatus)
                            }, CommandType.Text);
                    }
                    if (oLinkCls.GetForProcess == 1)
                    {
                        string CurrentProcessUser = WebSessionUtility.GetCurrentLoginUser().LoginName;
                        string CurrentProcessFullName = WebSessionUtility.GetCurrentLoginUser().FullName;
                        string CommandText =
                                " Update TableWorkflowAction set CurrentProcessUser=@CurrentProcessUser,CurrentProcessFullName=@CurrentProcessFullName,ProcessType='view' where GroupBatchId=@GroupBatchId and Id<>@WorkflowActionId";
                        DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                            dbTransaction,
                            CommandText,
                            new Model.DatabaseParamCls[]{
                                             new Model.DatabaseParamCls("GroupBatchId",GroupBatchId),
                                             new Model.DatabaseParamCls("WorkflowActionId",WorkflowActionId),
                                             new Model.DatabaseParamCls("CurrentProcessUser",CurrentProcessUser),
                                             new Model.DatabaseParamCls("CurrentProcessFullName",CurrentProcessFullName),
                                             new Model.DatabaseParamCls("WorkflowStatus",NextStatus),
                                             new Model.DatabaseParamCls("ViewParam",NextStatus)
                                     }, CommandType.Text);
                    }

                    if (oLinkCls.DeleteAfterNext == 1)
                    {
                        if (DedicateUsers.Length > 0)
                        {
                            //trong truong hop co doi tuong chuyen thi xoa
                            string CommandText =
                                //" Delete from TableWorkflowActionAttachFile where frkWorkflowActionId in (select Id from TableWorkflowAction where BatchId=@BatchId); " +
                                " Delete from TableWorkflowAction where BatchId=@BatchId";
                            DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                                dbTransaction,
                                CommandText,
                                new Model.DatabaseParamCls[]{
                                             new Model.DatabaseParamCls("BatchId",BatchId)
                                     }, CommandType.Text);
                        }
                        else
                        {
                            if (oLinkCls.GetForProcess == 0)
                            {
                                //xoa nhung thang lien quan...! 
                                string CommandText =
                                    //" Delete from TableWorkflowActionAttachFile where frkWorkflowActionId in (select Id from TableWorkflowAction where BatchId=@BatchId and Id<>@Id); " +
                                    " Delete from TableWorkflowAction where BatchId=@BatchId and Id<>@Id";
                                DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                                    dbTransaction,
                                    CommandText,
                                    new Model.DatabaseParamCls[]{
                                             new Model.DatabaseParamCls("BatchId",BatchId),
                                             new Model.DatabaseParamCls("Id",WorkflowActionId),
                                     }, CommandType.Text);
                            }
                        }
                    }
                }




                if (oLinkCls.FinishThisTask != 0)
                {
                    string RunCommandText = "Update TableRunningWorkflowTask set ProcessBy=@ProcessBy, WorkingStatus=N'Hoàn thành',CurrentDate=@CurrentDate,DaysForProcess=@DaysForProcess where ObjectRecordId=@ObjectRecordId";
                    DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                        dbTransaction,
                        RunCommandText,
                        new Model.DatabaseParamCls[]{
                                    new Model.DatabaseParamCls("CurrentDate",System.DateTime.Now),
                                    new Model.DatabaseParamCls("DaysForProcess",0),
                                    new Model.DatabaseParamCls("ObjectRecordId",RecordId),
                                    new Model.DatabaseParamCls("ProcessBy",ComeFrom),
                            }, CommandType.Text);


                    string CommandText = "Update TableWorkflowAction set ProcessDone=1,Sent=1 where Id=@Id";
                    DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                        dbTransaction,
                        CommandText,
                        new Model.DatabaseParamCls[]{
                            new Model.DatabaseParamCls("Id",LinkParentId)
                        }, CommandType.Text);

                    if (ParentWaitingTasksId != null)
                    {
                        CommandText = "Update TableWorkflowAction set WaitingTasks=WaitingTasks-1 where WaitingTasks>0 and Id=@Id";
                        DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                        dbTransaction,
                        CommandText,
                        new Model.DatabaseParamCls[]{
                            new Model.DatabaseParamCls("Id",ParentWaitingTasksId)
                        }, CommandType.Text);
                    }
                    if (WaitingTasks == 0)
                    {
                        CommandText = " Update TableWorkflowAction set Sent=-1 where LinkBatchId=@LinkBatchId";
                        DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                          dbTransaction,
                          CommandText,
                          new Model.DatabaseParamCls[]{
                                new Model.DatabaseParamCls("LinkBatchId",LinkBatchId)
                            }, CommandType.Text);
                    }



                    if (oLinkCls.FinishThisTask == 2)
                    {
                        //if (oLinkCls.DeleteAfterNext == 1)
                        {
                            //trong truong hop co doi tuong chuyen thi xoa
                            if (DedicateUsers.Length > 0)
                            {
                                CommandText =
                                    //" Delete from TableWorkflowActionAttachFile where frkWorkflowActionId in (select Id from TableWorkflowAction where GroupBatchId=@GroupBatchId); " +
                                    " Delete from TableWorkflowAction where GroupBatchId=@GroupBatchId";
                                DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                                    dbTransaction,
                                    CommandText,
                                    new Model.DatabaseParamCls[]{
                                             new Model.DatabaseParamCls("GroupBatchId",GroupBatchId)
                                     }, CommandType.Text);
                            }
                            else
                            {
                                //xoa nhung thang lien quan...! 
                                CommandText =
                                    //" Delete from TableWorkflowActionAttachFile where frkWorkflowActionId in (select Id from TableWorkflowAction where GroupBatchId=@GroupBatchId and Id<>@Id); " +
                                    " Delete from TableWorkflowAction where GroupBatchId=@GroupBatchId and Id<>@Id";
                                DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                                    dbTransaction,
                                    CommandText,
                                    new Model.DatabaseParamCls[]{
                                             new Model.DatabaseParamCls("GroupBatchId",GroupBatchId),
                                             new Model.DatabaseParamCls("Id",WorkflowActionId),
                                     }, CommandType.Text);
                            }
                        }

                        //doan nay xoa het cac thu lien quan den quy trinh di...!
                        //CommandText =
                        //        " Delete from TableWorkflowCurrentProcess where RecordId=@RecordId; " +
                        //        " Delete from TableWorkflowHasReceived where RecordId=@RecordId";
                        //DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                        //    dbTransaction,
                        //    CommandText,
                        //    new Model.DatabaseParamCls[]{
                        //                     new Model.DatabaseParamCls("RecordId",RecordId),
                        //             }, CommandType.Text);
                        ////DeleteRunningWorkflow((SqlTransaction)dbTransaction, RecordId);

                        ////xoa phan quyen
                        //CommandText =
                        //       " Delete from TableWorkflowPermissionGrant where ObjectId=@ObjectId";
                        //DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                        //    dbTransaction,
                        //    CommandText,
                        //    new Model.DatabaseParamCls[]{
                        //                     new Model.DatabaseParamCls("ObjectId",RecordId),
                        //             }, CommandType.Text);
                    }


                    //xoa quyen

                    dbTransaction.Commit();
                    return oDoNextLinkRunAtServerReturnCls;
                }
                if (hasBeginTrans == false)
                {
                    dbTransaction.Commit();
                }
                return oDoNextLinkRunAtServerReturnCls;
            }
            catch (Exception ex)
            {
                if (hasBeginTrans == false)
                {
                    dbTransaction.Rollback();
                }
                throw (ex);
            }
        }

        public DoNextLinkRunAtServerReturnCls DoNextLink(
            Model.WsInParamCls oWsInParamCls,
            ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            DoNextLinkRunAtServerReturnCls oDoNextLinkRunAtServerReturnCls = new DoNextLinkRunAtServerReturnCls();
            string LinkId = oWsInParamCls.KeyId;
            string XmlData = oWsInParamCls.Xml;
            DataSet ds = new DataSet();
            ds.ReadXml(new StringReader(XmlData));
            string RunningWorkflowTaskId = ds.Tables[0].Rows[0]["RunningWorkflowTaskId"].ToString();
            string WorkflowActionId = ds.Tables[0].Rows[0]["WorkflowActionId"].ToString();
            string AttachFileSessionId = ds.Tables[0].Rows[0]["AttachFileSessionId"].ToString();
            string AttachedDocumentIds = ds.Tables[0].Rows[0]["AttachedDocumentIds"].ToString();
            string FlashQueuePath = ds.Tables[0].Rows[0]["FlashQueuePath"].ToString();
            string Note = "";
            try
            {
                Note = ds.Tables[0].Rows[0]["Note"].ToString();
            }
            catch { }


            string ResponsibleId = "";
            try
            {
                ResponsibleId = ds.Tables[0].Rows[0]["ResponsibleId"].ToString();
            }
            catch { }
            string Responsible = "";
            try
            {
                Responsible = ds.Tables[0].Rows[0]["Responsible"].ToString();
            }
            catch { }
            string JoinerId = "";
            try
            {
                JoinerId = ds.Tables[0].Rows[0]["JoinerId"].ToString();
            }
            catch { }
            string Joiner = "";
            try
            {
                Joiner = ds.Tables[0].Rows[0]["Joiner"].ToString();
            }
            catch { }


            string XmlUsers = ds.Tables[0].Rows[0]["XmlUsers"].ToString();
            string ProcessDays = "2";
            try
            {
                ProcessDays = ds.Tables[0].Rows[0]["ProcessDays"].ToString();
            }
            catch { }

            string WorkflowFunction = "";
            try
            {
                WorkflowFunction = ds.Tables[0].Rows[0]["WorkflowFunction"].ToString();
            }
            catch { }


            return DoNextLink(oWsInParamCls, null, LinkId, WorkflowActionId, Note, XmlUsers, XmlData, ProcessDays, WorkflowFunction, AttachFileSessionId, AttachedDocumentIds, FlashQueuePath, ResponsibleId, Responsible, JoinerId, Joiner);
        }





        public void InternalReadingHistoryLinks(
            Model.WsInParamCls oWsInParamCls,
            string Id,
            ref DataSet dsHistory)
        {
            string CommandText = "select * from TableWorkflowAction where Id='" + Id + "'";
            DataSet dsResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(CommandText);
            if (dsHistory == null)
            {
                dsHistory = dsResult.Clone();
            }
            if (dsResult.Tables[0].Rows.Count == 0) return;
            for (int iIndex = 0; iIndex < dsResult.Tables[0].Rows.Count; iIndex++)
            {
                DataRow dr = dsHistory.Tables[0].NewRow();
                for (int iCol = 0; iCol < dsHistory.Tables[0].Columns.Count; iCol++)
                {
                    dr[iCol] = dsResult.Tables[0].Rows[iIndex][iCol];
                }
                dsHistory.Tables[0].Rows.Add(dr);
                string LinkParentId = null;
                if (dsResult.Tables[0].Rows[iIndex]["LinkParentId"] != DBNull.Value)
                {
                    LinkParentId = (string)dsResult.Tables[0].Rows[iIndex]["LinkParentId"];
                    InternalReadingHistoryLinks(oWsInParamCls, LinkParentId, ref dsHistory);
                }
            }
        }


        public void ReadingHistoryLinks(
             Model.WsInParamCls oWsInParamCls,
             ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string WorkflowActionId = oWsInParamCls.KeyId;
            InternalReadingHistoryLinks(oWsInParamCls, WorkflowActionId, ref oWsReturnParamCls.dsResult);
        }

        public void DeleteWorkflow(
             Model.WsInParamCls oWsInParamCls,
             ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string WorkflowDefId = oWsInParamCls.KeyId;
            string CommandText =
                                 //" Delete from TableWorkflowActionAttachFile where WorkflowDefId=@WorkflowDefId; " +
                                 //" Delete from TableWorkflowAttachFile where WorkflowDefId=@WorkflowDefId; " +
                                 //" Delete from TableWorkflowActionHistory where WorkflowDefId=@WorkflowDefId;" +
                                 " Delete from TableWorkflowAction where WorkflowDefId=@WorkflowDefId;" +
                                 " Delete from TableWorkflowDefVersion where frkWorkflowDefId=@WorkflowDefId;" +
                                 " Delete from TableWorkflowDefMapRole where frkWorkflowDefId=@WorkflowDefId;" +
                                 //" Delete from TableWorkflowHasReceived where frkWorkflowDefId=@WorkflowDefId;" +
                                 //" Delete from TableWorkflowHasSent where frkWorkflowDefId=@WorkflowDefId;" +
                                 " Delete from TableRunningWorkflowtask where WorkFlowDefId=@WorkflowDefId;" +
                                 " Delete from TableWorkflowControl where WorkflowDefId=@WorkflowDefId;"+
                                 " Delete from TableWorkflowDef where WorkflowDefId=@WorkflowDefId;";
            DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).ExecuteNonQuery(
                CommandText,
                new Model.DatabaseParamCls[]
                {
                    new Model.DatabaseParamCls("WorkflowDefId",WorkflowDefId)
                });
        }




        public static DataTable ReadingHistory(string ConnectionString, string WorkFlowDefId, string RecordId)
        {
            SqlConnection sqlConnection = new SqlConnection(ConnectionString);
            SqlCommand sqlCommand = sqlConnection.CreateCommand();
            sqlCommand.CommandText = "select * from TableWorkFlowActionHistory where WorkFlowDefId='" + WorkFlowDefId + "' and RecordId='" + RecordId + "' order by [ActionDate]";
            DataTable dtResult = new DataTable();
            SqlDataAdapter da = new SqlDataAdapter(sqlCommand);
            da.Fill(dtResult);

            return dtResult;
        }

        public static WorkFlowApp CreateWorkflowAppFromWorkflowAction(string ConnectionString, string WorklowActionId)
        {
            SqlConnection sqlConnection = new SqlConnection(ConnectionString);
            string CommandText = "select XmlWorkflowData from TableWorkflowAction "+
                                "   join TableRunningWorkflowTask on TableRunningWorkflowTask.RunningWorkflowTaskId = TableWorkflowAction.RunningWorkflowTaskId " +
                                " where Id='" + WorklowActionId + "'";
            SqlCommand sqlCommand = sqlConnection.CreateCommand();
            sqlCommand.CommandText = CommandText;
            DataTable dtResult = new DataTable();
            SqlDataAdapter da = new SqlDataAdapter(sqlCommand);
            da.Fill(dtResult);
            if (dtResult.Rows.Count == 0)
            {
                throw new Exception("Dữ liệu đã bị xóa! Không lấy được quy trình để thực hiện!");
            }
            string XmlWorkflowData = (string)dtResult.Rows[0]["XmlWorkflowData"];
            WorkFlowApp wf = new WorkFlowApp(XmlWorkflowData);
            return wf;
        }

        public static WorkFlowRecordCls CreateWorkFlowRecord(string ConnectionString, string Id)
        {
            SqlConnection sqlConnection = new SqlConnection(ConnectionString);
            SqlCommand sqlCommand = sqlConnection.CreateCommand();
            sqlCommand.CommandText = "select TableWorkFlowAction.* from TableWorkFlowAction where Id='" + Id + "'";
            DataTable dtResult = new DataTable();
            SqlDataAdapter da = new SqlDataAdapter(sqlCommand);
            da.Fill(dtResult);
            if (dtResult.Rows.Count == 0) return null;
            WorkFlowRecordCls WorkFlowRecordCls = new WorkFlowRecordCls();
            WorkFlowRecordCls.Id = Id;

            if (dtResult.Rows[0]["BatchId"] != DBNull.Value)
            {
                WorkFlowRecordCls.BatchId = (string)dtResult.Rows[0]["BatchId"];
            }
            WorkFlowRecordCls.WorkFlowDefId = (string)dtResult.Rows[0]["WorkFlowDefId"];
            WorkFlowRecordCls.WorkflowDefName = (string)dtResult.Rows[0]["WorkflowDefName"];
            WorkFlowRecordCls.EmployeeId = (string)dtResult.Rows[0]["EmployeeId"];
            WorkFlowRecordCls.RecordId = (string)dtResult.Rows[0]["RecordId"];
            WorkFlowRecordCls.RecordNote = (string)dtResult.Rows[0]["RecordNote"];
            WorkFlowRecordCls.Subject = (string)dtResult.Rows[0]["Subject"];
            WorkFlowRecordCls.ActionDate = (DateTime)dtResult.Rows[0]["ActionDate"];
            WorkFlowRecordCls.ProcessId = (string)dtResult.Rows[0]["ProcessId"];
            WorkFlowRecordCls.ViewParam = (string)dtResult.Rows[0]["ViewParam"];
            WorkFlowRecordCls.ComeFrom = (string)dtResult.Rows[0]["ComeFrom"];
            WorkFlowRecordCls.ComeFromName = (string)dtResult.Rows[0]["ComeFromName"];

            if (dtResult.Rows[0]["ComeFromOffice"] != DBNull.Value)
            {
                WorkFlowRecordCls.ComeFromOffice = (string)dtResult.Rows[0]["ComeFromOffice"];
            }
            try
            {
                WorkFlowRecordCls.LinkId = (string)dtResult.Rows[0]["LinkId"];
            }
            catch { }

            try
            {
                WorkFlowRecordCls.PriorityId = (string)dtResult.Rows[0]["PriorityId"];
            }
            catch { }

            try
            {
                WorkFlowRecordCls.PriorityText = (string)dtResult.Rows[0]["PriorityText"];
            }
            catch { }
            try
            {
                WorkFlowRecordCls.PreviewUrl = (string)dtResult.Rows[0]["PreviewUrl"];
            }
            catch { }
            try
            {
                WorkFlowRecordCls.DelayNote = (string)dtResult.Rows[0]["DelayNote"];
            }
            catch { }
            try
            {
                WorkFlowRecordCls.ExtraInfo = (string)dtResult.Rows[0]["ExtraInfo"];
            }
            catch { }
            try
            {
                WorkFlowRecordCls.ExtraData = (string)dtResult.Rows[0]["ExtraData"];
            }
            catch { }
            try
            {
                WorkFlowRecordCls.XmlData = (string)dtResult.Rows[0]["XmlData"];
            }
            catch { }
            try
            {
                WorkFlowRecordCls.fromOfficeCode = (string)dtResult.Rows[0]["fromOfficeCode"];
            }
            catch { }
            try
            {
                WorkFlowRecordCls.toOfficeCode = (string)dtResult.Rows[0]["toOfficeCode"];
            }
            catch { }
            try
            {
                WorkFlowRecordCls.Sent = (int)dtResult.Rows[0]["Sent"];
            }
            catch { }


            return WorkFlowRecordCls;
        }



        public static string ServerSideGetWorkflowDefName(string ConnectionString, string WorkflowDefId)
        {
            SqlConnection sqlConnection = new SqlConnection(ConnectionString);
            SqlCommand sqlCommand = sqlConnection.CreateCommand();
            sqlCommand.CommandText = "select WorkflowName from TableWorkflowDef where WorkflowDefId='" + WorkflowDefId + "'";
            DataTable dtResult = new DataTable();
            SqlDataAdapter da = new SqlDataAdapter(sqlCommand);
            da.Fill(dtResult);
            if (dtResult.Rows.Count == 0) return null;
            return (string)dtResult.Rows[0]["WorkflowName"];
        }

        public static WorkFlowRecordCls CreateWorkFlowRecordByRecordId(
            string ConnectionString,
            string RecordId,
            string BatchId)
        {
            SqlConnection sqlConnection = new SqlConnection(ConnectionString);
            SqlCommand sqlCommand = sqlConnection.CreateCommand();
            sqlCommand.CommandText = "select * from TableWorkFlowAction where RecordId='" + RecordId + "' and BatchId='" + BatchId + "'";
            DataTable dtResult = new DataTable();
            SqlDataAdapter da = new SqlDataAdapter(sqlCommand);
            da.Fill(dtResult);
            if (dtResult.Rows.Count == 0) return null;
            string Id = (string)dtResult.Rows[0]["Id"];
            return CreateWorkFlowRecord(ConnectionString, Id);
        }

        public void ProcessLogin(
            WsInParamCls oWsInParamCls,
            ref WsReturnParamCls oWsReturnParamCls)
        {
            UserCls oUserCls = new UserCls(oWsInParamCls.Xml);
            string Password = oUserCls.Password;// "";// new RSACSPCls().Encrypt("vvvxxx!@#$abc*()", oUserCls.Password);

            DataTable dt = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(
                " Update TableUser set Locked=0 where Locked is null; " +
                " select * from TableUser " +
                "   where LoginName=@LoginName and Password=@Password and Locked=0",
                new DatabaseParamCls[]{
                    new DatabaseParamCls("LoginName",oUserCls.LoginName),
                    new DatabaseParamCls("Password", Password )
            });
            if (dt.Rows.Count == 0)
            {
                string MsgText = "Tài khoản hoặc mật khẩu không hợp lệ!";
                throw new Exception(MsgText);
            }
            //doan nay add session


            oUserCls.UserId = (string)dt.Rows[0]["UserId"];
            oUserCls.LoginName = (string)dt.Rows[0]["LoginName"];
            oUserCls.FullName = (string)dt.Rows[0]["FullName"];
            try
            {
                oUserCls.Address = (string)dt.Rows[0]["Address"];
            }
            catch { }
            try
            {
                oUserCls.Tel = (string)dt.Rows[0]["Tel"];
            }
            catch { }
            try
            {
                oUserCls.Fax = (string)dt.Rows[0]["Fax"];
            }
            catch { }


            oWsReturnParamCls.XmlResult = oUserCls.GetXml();
        }


        public void ReadingRoles(
           WsInParamCls oWsInParamCls,
           ref WsReturnParamCls oWsReturnParamCls)
        {
            string Keyword = oWsInParamCls.Keyword;
            Keyword = DatabaseServiceBll.ProcessSearchKeyword(Keyword);
            string Query = " select * from TableRole where 1=1 ";
            if (!String.IsNullOrEmpty(Keyword))
            {
                Query += " and RoleName like N'%" + Keyword + "%'";
            }
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(Query, null);
            oWsReturnParamCls.dsResult = ds;
        }

        public void ReadingRoleRelationTemplate(
           WsInParamCls oWsInParamCls,
           ref WsReturnParamCls oWsReturnParamCls)
        {
            string Keyword = oWsInParamCls.Keyword;
            Keyword = DatabaseServiceBll.ProcessSearchKeyword(Keyword);
            string Query = " select * from TableRoleRelationTemplate where 1=1 ";
            if (!String.IsNullOrEmpty(Keyword))
            {
                Query += " and RoleRelationTemplateName like N'%" + Keyword + "%'";
            }
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(Query, null);
            oWsReturnParamCls.dsResult = ds;
        }


        public void ReadingUsers(
           WsInParamCls oWsInParamCls,
           ref WsReturnParamCls oWsReturnParamCls)
        {
            string Keyword = oWsInParamCls.Keyword;
            string RoleId = oWsInParamCls.KeyId;
            Keyword = DatabaseServiceBll.ProcessSearchKeyword(Keyword);
            string Query =
                " select * from TableUser where 1=1 ";
            if (!String.IsNullOrEmpty(Keyword))
            {
                Query += " and (LoginName like N'%" + Keyword + "%' or Name like N'%" + Keyword + "%')";
            }
            if (String.IsNullOrEmpty(RoleId) == false)
            {
                Query += " and UserId in " +
                         "    (" +
                         "          select frkUserId from TableUserRole" +
                         "              where frkRoleId='" + RoleId + "'" +
                         "    )";
            }
            DataSet ds = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSetByDataSet(Query, null);
            oWsReturnParamCls.dsResult = ds;
        }


        public bool Process(Model.WsInParamCls oWsInParamCls, ref Model.WsReturnParamCls oWsReturnParamCls)
        {
            string ProcessorId = oWsInParamCls.ProcessorId;
            string LicenceCode = oWsInParamCls.LicenceCode;
            bool LicenceOk = true;
            oWsReturnParamCls.LicenceCode = LicenceCode;
            oWsReturnParamCls.ProcessorId = ProcessorId;
            if (LicenceOk == false)
            {
                oWsReturnParamCls.ReturnMsg = "Invalid licence code! Regcode is [" + ProcessorId + "]";
                oWsReturnParamCls.XmlResult = ProcessorId;
                oWsReturnParamCls.ProcessorId = ProcessorId;
                oWsReturnParamCls.LicenceCode = LicenceCode;
                oWsReturnParamCls.ReturnType = Model.EReturnType.InvalidLicence;
                return true;
            }

            //SystemLogin
            if (oWsInParamCls.Command.ToLower().Equals(eWorkflowCommand.SystemLogin.ToString().ToLower()))
            {
                ProcessLogin(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //ReadingRoles
            if (oWsInParamCls.Command.ToLower().Equals(eWorkflowCommand.ReadingRoles.ToString().ToLower()))
            {
                ReadingRoles(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //ReadingRoleRelationTemplate
            if (oWsInParamCls.Command.ToLower().Equals(eWorkflowCommand.ReadingRoleRelationTemplate.ToString().ToLower()))
            {
                ReadingRoleRelationTemplate(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //ReadingUsers
            if (oWsInParamCls.Command.ToLower().Equals(eWorkflowCommand.ReadingUsers.ToString().ToLower()))
            {
                ReadingUsers(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //ReadingWorkflowList
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.ReadingWorkflowList.ToString().ToLower()))
            {
                ReadingWorkflowList(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //GetWorkflowData
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.GetWorkflowData.ToString().ToLower()))
            {
                GetWorkflowData(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //ReadingMyTask
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.ReadingMyTask.ToString().ToLower()))
            {
                ReadingMyTask(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //ReadingSentTasks
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.ReadingSentTasks.ToString().ToLower()))
            {
                ReadingSentTasks(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //ReadingWaitTasks
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.ReadingWaitTasks.ToString().ToLower()))
            {
                ReadingWaitTasks(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }
            //ReadingHistoryLinks
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.ReadingHistoryLinks.ToString().ToLower()))
            {
                ReadingHistoryLinks(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //StartWorkFlow
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.StartWorkFlow.ToString().ToLower()))
            {
                StartWorkFlow(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //SaveWorkflow
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.SaveWorkflow.ToString().ToLower()))
            {
                SaveWorkflow(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //GetNextLinks
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.GetNextLinks.ToString().ToLower()))
            {
                GetNextLinks(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //GetWfLink
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.GetWfRoleInLink.ToString().ToLower()))
            {
                GetWfRoleInLink(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //GetWfUsersInRole
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.GetWfUsersInRole.ToString().ToLower()))
            {
                //GetWfUsersInRole(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }
            //DoNextLink
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.DoNextLink.ToString().ToLower()))
            {
                DoNextLink(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //GetXmlWorkflowDataByWorkflowAction
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.GetXmlWorkflowDataByWorkflowAction.ToString().ToLower()))
            {
                GetXmlWorkflowDataByWorkflowAction(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //GetActiveWorkflowData
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.GetActiveWorkflowData.ToString().ToLower()))
            {
                GetActiveWorkflowData(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //GetAllVersionWorkflowData
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.GetAllVersionWorkflowData.ToString().ToLower()))
            {
                GetAllVersionWorkflowData(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //SetActiveVersion
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.SetActiveVersion.ToString().ToLower()))
            {
                SetActiveVersion(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }

            //DeleteWorkflow
            if (oWsInParamCls.Command.ToLower().Equals(Model.eWorkflowCommand.DeleteWorkflow.ToString().ToLower()))
            {
                DeleteWorkflow(oWsInParamCls, ref oWsReturnParamCls);
                return true;
            }
            return false;
        }



        public static string ServerSideGetPlugInAttachedFileHtml(
            string ConnectionString,
            string WorkflowActionId,
            bool AllowSelect)
        {
            string Html = "";
            string Query = " select WorkflowAttachFileId,AttachFilename,AttachedDate,AttachedBy, Ext,SaveFile from TableWorkflowActionAttachFile" +
                            "   join TableWorkflowAttachFile on TableWorkflowAttachFile.WorkflowAttachFileId=frkWorkflowAttachFileId" +
                            " where frkWorkflowActionId=@WorkflowActionId";
            WsInParamCls oWsInParamCls = new WsInParamCls();
            oWsInParamCls.ConnectionString = ConnectionString;
            DataTable dtResult = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(
              Query,
              new DatabaseParamCls[]{
                    new DatabaseParamCls("WorkflowActionId",WorkflowActionId),
                });
            if (dtResult.Rows.Count == 0)
            {
                return "";
            }
            Html +=
                    "<div class=\"cssHeading\">Tài liệu gắn kèm trong quy trình</div>\r\n" +
                    "<input id=\"txtMaxAttachedDocument\" type=\"hidden\" value=\"" + dtResult.Rows.Count + "\">\r\n" +
                    "<div class=\"tabcontent\">\r\n" +
                    "<table>\r\n";
            for (int iIndex = 0; iIndex < dtResult.Rows.Count; iIndex++)
            {
                string WorkflowAttachFileId = (string)dtResult.Rows[iIndex]["WorkflowAttachFileId"];
                string AttachFilename = (string)dtResult.Rows[iIndex]["AttachFilename"];
                DateTime AttachedDate = (DateTime)dtResult.Rows[iIndex]["AttachedDate"];
                string AttachedBy = (string)dtResult.Rows[iIndex]["AttachedBy"];
                Html += " <tr>\r\n" +
                          "     <td width=\"10\">&nbsp;</td>\r\n";
                if (AllowSelect)
                {
                    Html += "     <td width=\"10\"><input type=\"hidden\" id=\"txtIndex" + iIndex + "\" value=\"" + WorkflowAttachFileId + "\"><input checked type=checkbox id=chk" + iIndex + "></td>\r\n";
                }
                Html +=
                          "     <td>" + AttachFilename + "</td>\r\n" +
                          "     <td>" + AttachedDate.ToString("dd/MM/yyyy HH:mm") + "</td>\r\n" +
                          "     <td>" + AttachedBy + "</td>\r\n" +
                          "     <td>(<a href=\"javascript:ClientViewAttachFileInWorkflow('" + WorkflowAttachFileId + "');\">Tải liên kết</a>)</td>\r\n" +
                          "     <td><div id=\"div" + WorkflowAttachFileId + "\"></div></td>\r\n" +
                          " </tr>\r\n";
            }
            Html += "</table>\r\n" +
                    "</div>\r\n";
            return Html;
        }

        //[AjaxPro.AjaxMethod]
        //public string ServerSideGetPreviewUrl(string SiteId, string WorkflowAttachFileId)
        //{
        //    try
        //    {
        //        SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);

        //        Model.WsInParamCls oWsInParamCls = new Model.WsInParamCls();
        //        oWsInParamCls.ConnectionString = oSiteParam.ConnectionString;

        //        DataTable dt = DatabaseServiceBll.CreateDatabaseService(oWsInParamCls).GetRecordSet(
        //            " select SaveFile,AttachFileName from TableWorkflowAttachFile where WorkflowAttachFileId=@WorkflowAttachFileId", new DatabaseParamCls[]{
        //            new DatabaseParamCls("WorkflowAttachFileId",WorkflowAttachFileId)
        //        });
        //        //doan nay save ra file template...!

        //        string AttachFileName = (string)dt.Rows[0]["AttachFileName"];
        //        string Ext = new System.IO.FileInfo(AttachFileName).Extension;
        //        Portal.Environment.BlobFieldReturn oBlobFieldReturn =
        //            Portal.Environment.BobController.ReadBlobField(SiteId, oSiteParam.ConnectionString, "TableWorkflowAttachFile", "Body", "FlashContent", "WorkflowAttachFileId", WorkflowAttachFileId, AttachFileName, Ext, true);

        //        return oBlobFieldReturn.Url;
        //    }
        //    catch (Exception ex)
        //    {
        //        return "ERROR: " + ex.Message.ToString();
        //    }
        //}


        public static DataTable ReadingWorkflowHistoryForObject(
            string ConnectionString,
            string ObjectId)
        {
            SqlConnection sqlConnection = new SqlConnection(ConnectionString);
            SqlCommand sqlCommand = sqlConnection.CreateCommand();
            sqlCommand.CommandText = "select TableDocumentNextHistory.*,LoginName,FullName from TableDocumentNextHistory" +
                                     "      left outer join TableUser on TableUser.UserId=TableDocumentNextHistory.ProcessUser" +
                                     "  where ObjectId='" + ObjectId + "' order by ActionDate";
            DataTable dtResult = new DataTable();
            SqlDataAdapter da = new SqlDataAdapter(sqlCommand);
            da.Fill(dtResult);

            return dtResult;
        }

        public static DataTable ReadingLastWorkflowHistoryForObject(
            string ConnectionString,
            string ObjectId)
        {
            SqlConnection sqlConnection = new SqlConnection(ConnectionString);
            SqlCommand sqlCommand = sqlConnection.CreateCommand();
            sqlCommand.CommandText = "select top 1 TableDocumentNextHistory.*,LoginName,FullName from TableDocumentNextHistory" +
                                     "      left outer join TableUser on TableUser.UserId=TableDocumentNextHistory.ProcessUser" +
                                     "  where ObjectId='" + ObjectId + "' order by ActionDate DESC";
            DataTable dtResult = new DataTable();
            SqlDataAdapter da = new SqlDataAdapter(sqlCommand);
            da.Fill(dtResult);

            return dtResult;
        }

        public static DataTable ReadingDocumentNextHistoryAttachFile(
           string ConnectionString, string DocumentNextHistoryId)
        {
            SqlConnection sqlConnection = new SqlConnection(ConnectionString);
            SqlCommand sqlCommand = sqlConnection.CreateCommand();
            sqlCommand.CommandText = " select DocumentNextHistoryAttachFileId,RealFile,AttachedDate,AttachedBy from TableDocumentNextHistoryAttachFile" +
                                     "  where frkDocumentNextHistoryId='" + DocumentNextHistoryId + "' order by AttachedDate";
            DataTable dtResult = new DataTable();
            SqlDataAdapter da = new SqlDataAdapter(sqlCommand);
            da.Fill(dtResult);

            return dtResult;
        }

        public string GetDocumentNextHistoryAttachFile(
            string ConnectionString,
            string DocumentNextHistoryAttachFileId)
        {
            SqlConnection sqlConnection = new SqlConnection(ConnectionString);
            SqlCommand sqlCommand = sqlConnection.CreateCommand();
            sqlCommand.CommandText = " select RealFile from TableDocumentNextHistoryAttachFile where DocumentNextHistoryAttachFileId='" + DocumentNextHistoryAttachFileId + "'";
            DataTable dtResult = new DataTable();
            SqlDataAdapter da = new SqlDataAdapter(sqlCommand);
            da.Fill(dtResult);

            return (string)dtResult.Rows[0]["RealFile"];
        }

        //[AjaxPro.AjaxMethod]
        //public string ServerSideDownloadAttachFileInWorkflow(string SiteId, string DocumentNextHistoryAttachFileId)
        //{
        //    try
        //    {
        //        SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);
        //        string RealFile = GetDocumentNextHistoryAttachFile(oSiteParam.ConnectionString, DocumentNextHistoryAttachFileId);
        //        string Ext = new System.IO.FileInfo(RealFile).Extension;
        //        Portal.Environment.BlobFieldReturn oBlobFieldReturn = Portal.Environment.BobController.ReadBlobField(SiteId, oSiteParam.ConnectionString, "TableDocumentNextHistoryAttachFile", "ContentFile", "FlashContent", "DocumentNextHistoryAttachFileId", DocumentNextHistoryAttachFileId, RealFile, Ext, true);
        //        return oBlobFieldReturn.Url;

        //    }
        //    catch (Exception ex)
        //    {
        //        return "ERROR: " + ex.Message.ToString();
        //    }
        //}


        public static string ServerSideGetWorkflowHistoryJavascript()
        {
            string javascriptText =
                      "<script language=javascript>\r\n" +
                      " function ClientDownloadHistoryAttachAttachFile(DocumentNextHistoryAttachFileId)\r\n" +
                      " {\r\n" +
                      "     SiteId=document.getElementById('txtSiteParam').value;\r\n" +
                      "     Url=Portal.Workflow.Bussiness.WorkflowBll.ServerSideDownloadAttachFileInWorkflow(SiteId, DocumentNextHistoryAttachFileId).value;\r\n" +
                      "     if(Url.indexOf('ERROR')!=-1)\r\n" +
                      "     {\r\n" +
                      "         alert(Url);\r\n" +
                      "         return;\r\n" +
                      "     }\r\n" +
                      "     window.open(Url,'_blank');\r\n" +
                      " }\r\n" +

                      " function ClientShowHiddenHistory()\r\n" +
                      " {\r\n" +
                      "     var ele = document.getElementById(\"divHistoryContent\");\r\n" +
                      "     if(ele.style.display == \"block\") {\r\n" +
                      "          ele.style.display = \"none\";\r\n" +
                      "          document.getElementById('ButtonHiddenShow').value='Hiện lịch sử';\r\n" +
                      "     }\r\n" +
                      "     else {\r\n" +
                      "          document.getElementById('ButtonHiddenShow').value='Ẩn lịch sử';\r\n" +
                      "      ele.style.display = \"block\";\r\n" +
                      "     }\r\n" +
                      " }\r\n" +
                      "</script>\r\n";
            return javascriptText;
        }

        public static AjaxOut ServerSideGetWorkflowHistory(
            string SiteId,
            string ConnectionString,
            string ObjectId,
            bool Expand)
        {
            AjaxOut OAjaxOut = new AjaxOut();
            try
            {
                DataTable dtNextHistory = ReadingWorkflowHistoryForObject(ConnectionString, ObjectId);
                string Html = "";
                string Display = "block";
                string Caption = "Ẩn lịch sử";
                if (Expand == false)
                {
                    Display = "none";
                    Caption = "Hiện lịch sử";
                }
                if (dtNextHistory.Rows.Count > 0)
                {
                    Html +=
                              "<div><H3>Lịch sử luân chuyển quy trình (" + dtNextHistory.Rows.Count.ToString("#,##0") + ")</H3></div>\r\n" +
                        //"<div><input id=\"ButtonHiddenShow\" type=button class=button value=\""+Caption+"\" onclick=\"javascript:ClientShowHiddenHistory();\"></div>\r\n"+
                              "<div class=\"tabcontent\" id=\"divHistoryContent\" style=\"display:" + Display + ";\">\r\n" +
                              "<table class=\"FormSaveUpdate\">" +
                              "<tr>" +
                              "   <th>#</th>" +
                              "   <th>Ngày chuyển</th>" +
                              "   <th>Người chuyển</th>" +
                              "   <th>Người nhận</th>" +
                              "   <th>Ý kiến</th>" +
                        //"   <th>Tài liệu kèm</th>" +
                              "   <th>Trạng thái</th>" +
                              "</tr>";
                    //DataTable dtUser = Environment.Environments.ReadingUserForConvert(SiteId);
                    for (int iIndex = 0; iIndex < dtNextHistory.Rows.Count; iIndex++)
                    {
                        string DocumentNextHistoryId = (string)dtNextHistory.Rows[iIndex]["DocumentNextHistoryId"];
                        DateTime ActionDate = (DateTime)dtNextHistory.Rows[iIndex]["ActionDate"];
                        string ProcessUser = (string)dtNextHistory.Rows[iIndex]["ProcessUser"];
                        string ProcessNote = (string)dtNextHistory.Rows[iIndex]["ProcessNote"];
                        string LoginName = "";
                        try
                        {
                            LoginName = (string)dtNextHistory.Rows[iIndex]["LoginName"];
                        }
                        catch { }
                        string FullName = "";
                        try
                        {
                            FullName = (string)dtNextHistory.Rows[iIndex]["FullName"];
                        }
                        catch { }
                        //if (!string.IsNullOrEmpty(LoginName))
                        //{
                        //    ProcessUser = LoginName + " / " + FullName;
                        //}
                        ProcessUser = FullName;

                        string HistorySendToUsers = "";
                        if (dtNextHistory.Rows[iIndex]["HistorySendToUsers"] != DBNull.Value)
                        {
                            HistorySendToUsers = (string)dtNextHistory.Rows[iIndex]["HistorySendToUsers"];
                            HistorySendToUsers = HistorySendToUsers.Replace(";", "; ");
                        }

                        //HistorySendToUsers = Environment.Environments.CovertLoginToFullName(dtUser, HistorySendToUsers, 3);

                        string WorkflowNextLinkName = "";
                        if (dtNextHistory.Rows[iIndex]["WorkflowNextLinkName"] != DBNull.Value)
                        {
                            WorkflowNextLinkName = (string)dtNextHistory.Rows[iIndex]["WorkflowNextLinkName"];
                        }
                        DataTable dtAttachFile = ReadingDocumentNextHistoryAttachFile(ConnectionString, DocumentNextHistoryId);
                        string AttachFileText = "";
                        for (int iIndexAttachFile = 0; iIndexAttachFile < dtAttachFile.Rows.Count; iIndexAttachFile++)
                        {
                            string DocumentNextHistoryAttachFileId = (string)dtAttachFile.Rows[iIndexAttachFile]["DocumentNextHistoryAttachFileId"];
                            string RealFile = (string)dtAttachFile.Rows[iIndexAttachFile]["RealFile"];
                            DateTime AttachedDate = (DateTime)dtAttachFile.Rows[iIndexAttachFile]["AttachedDate"];
                            string AttachedBy = (string)dtAttachFile.Rows[iIndexAttachFile]["AttachedBy"];

                            AttachFileText += AttachedBy + "/" + AttachedDate.ToString("dd/MM/yyyy") + "/<a href=\"javascript:ClientDownloadHistoryAttachAttachFile('" + DocumentNextHistoryAttachFileId + "');\">" + RealFile + "</a>";
                            if (iIndexAttachFile < dtAttachFile.Rows.Count - 1)
                            {
                                AttachFileText = AttachFileText + "<br>";
                            }
                        }
                        Html +=
                        "   <tr>" +
                        "       <td valign=top>" + (iIndex + 1) + "</td>\r\n" +
                        "       <td valign=top  width=120>" + ActionDate.ToString("dd/MM/yyyy<br>Lúc: HH:mm") + "</td>" +
                        "       <td valign=top>" + ProcessUser + "</td>" +
                        "       <td valign=top>" + HistorySendToUsers + "</td>" +
                        "       <td valign=top>" + ProcessNote + "</td>" +
                            //"       <td valign=top>" + AttachFileText + "</td>" +
                        "       <td valign=top>" + WorkflowNextLinkName + "</td>" +
                        "   </tr>";
                    }
                    Html += "</table></div>";
                }
                OAjaxOut.HtmlContent = Html;
                OAjaxOut.RetNumber = dtNextHistory.Rows.Count;
            }
            catch (Exception ex)
            {
                OAjaxOut.Error = true;
                OAjaxOut.InfoMessage = ex.Message.ToString();
            }
            return OAjaxOut;
        }


        public static string GetLastWorkflowHistoryStatus(
           string SiteId,
           string ConnectionString,
           string ObjectId)
        {
            DataTable dtNextHistory = ReadingLastWorkflowHistoryForObject(ConnectionString, ObjectId);
            string WorkflowNextLinkName = "";
            if (dtNextHistory.Rows.Count > 0)
            {
                if (dtNextHistory.Rows[0]["WorkflowNextLinkName"] != DBNull.Value)
                {
                    WorkflowNextLinkName = (string)dtNextHistory.Rows[0]["WorkflowNextLinkName"];
                }
            }
            return WorkflowNextLinkName;
        }


        public static string GetWorkflowActionId(string ConnectionString, string RecordId)
        {
            string Query = " select Id from TableWorkFlowAction where ProcessType='to' and [sent]=0 and ProcessDone=0 and EmployeeLoginName=@LoginName and toRole=@RoleId and RecordId=@RecordId";
            SqlConnection oSqlConnection = new SqlConnection(ConnectionString);
            oSqlConnection.Open();
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@LoginName", SqlDbType.VarChar).Value = WebSessionUtility.GetCurrentLoginUser().LoginName;
            oSqlCommand.Parameters.Add("@RoleId", SqlDbType.VarChar).Value = WebSessionUtility.GetCurrentLoginUser().RoleId;
            oSqlCommand.Parameters.Add("@RecordId", SqlDbType.VarChar).Value = RecordId;
            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            DataTable dtResult = new DataTable();
            sqlda.Fill(dtResult);
            if (dtResult.Rows.Count == 0) return "";
            string Id = (string)dtResult.Rows[0]["Id"];
            return Id;
        }

        public class GetWorkflowCls
        {
            public string WorkflowActionId;
            public string WorkflowDefId;
            public string ProcessType = "to";
            public string CurrentProcessUser = "";
            public string CurrentProcessFullName = "";
            public string WorkflowStatus = "";
            public string ViewParam = "";
            public bool IsViewer
            {
                get
                {
                    return ProcessType.ToLower().Trim().Equals("view");
                }
            }
        }



        public static GetWorkflowCls GetWorkflowActionInfo(string ConnectionString, string RecordId)
        {
            GetWorkflowCls oGetWorkflowCls = new GetWorkflowCls();
            string Query = "select Id,WorkflowDefId,ProcessType,CurrentProcessUser=IsNull(CurrentProcessUser,''),CurrentProcessFullName=IsNull(CurrentProcessFullName,'') from TableWorkFlowAction where [sent]=0 and ProcessDone=0 and EmployeeLoginName=@LoginName and toRole=@RoleId and RecordId=@RecordId";
            SqlConnection oSqlConnection = new SqlConnection(ConnectionString);
            oSqlConnection.Open();
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@LoginName", SqlDbType.VarChar).Value = WebSessionUtility.GetCurrentLoginUser().LoginName;
            oSqlCommand.Parameters.Add("@RoleId", SqlDbType.VarChar).Value = WebSessionUtility.GetCurrentLoginUser().RoleId;
            oSqlCommand.Parameters.Add("@RecordId", SqlDbType.VarChar).Value = RecordId;
            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            DataTable dtResult = new DataTable();
            sqlda.Fill(dtResult);
            if (dtResult.Rows.Count == 0) return null;
            oGetWorkflowCls.WorkflowActionId = (string)dtResult.Rows[0]["Id"];
            oGetWorkflowCls.WorkflowDefId = (string)dtResult.Rows[0]["WorkflowDefId"];
            oGetWorkflowCls.ProcessType = (string)dtResult.Rows[0]["ProcessType"];
            oGetWorkflowCls.CurrentProcessUser = (string)dtResult.Rows[0]["CurrentProcessUser"];
            oGetWorkflowCls.CurrentProcessFullName = (string)dtResult.Rows[0]["CurrentProcessFullName"];
            return oGetWorkflowCls;
        }


        public static GetWorkflowCls GetWorkflowActionInfo(string ConnectionString, string WorkflowDefId, string RecordId)
        {
            GetWorkflowCls oGetWorkflowCls = new GetWorkflowCls();
            string Query = "select Id,WorkflowDefId,ProcessType,CurrentProcessUser=IsNull(CurrentProcessUser,''),CurrentProcessFullName=IsNull(CurrentProcessFullName,''),ViewParam=IsNull(ViewParam,''),WorkflowStatus=IsNull(WorkflowStatus,'') from TableWorkFlowAction where WorkflowDefId=@WorkflowDefId and [sent]=0 and ProcessDone=0 and EmployeeLoginName=@LoginName and toRole=@RoleId and RecordId=@RecordId";
            SqlConnection oSqlConnection = new SqlConnection(ConnectionString);
            oSqlConnection.Open();
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@LoginName", SqlDbType.VarChar).Value = WebSessionUtility.GetCurrentLoginUser().LoginName;
            oSqlCommand.Parameters.Add("@RoleId", SqlDbType.VarChar).Value = WebSessionUtility.GetCurrentLoginUser().RoleId;
            oSqlCommand.Parameters.Add("@RecordId", SqlDbType.VarChar).Value = RecordId;
            oSqlCommand.Parameters.Add("@WorkflowDefId", SqlDbType.VarChar).Value = WorkflowDefId;
            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            DataTable dtResult = new DataTable();
            sqlda.Fill(dtResult);
            if (dtResult.Rows.Count == 0) return null;
            oGetWorkflowCls.WorkflowActionId = (string)dtResult.Rows[0]["Id"];
            oGetWorkflowCls.WorkflowDefId = (string)dtResult.Rows[0]["WorkflowDefId"];
            oGetWorkflowCls.ProcessType = (string)dtResult.Rows[0]["ProcessType"];
            oGetWorkflowCls.CurrentProcessUser = (string)dtResult.Rows[0]["CurrentProcessUser"];
            oGetWorkflowCls.CurrentProcessFullName = (string)dtResult.Rows[0]["CurrentProcessFullName"];
            oGetWorkflowCls.ViewParam = (string)dtResult.Rows[0]["ViewParam"];
            oGetWorkflowCls.WorkflowStatus = (string)dtResult.Rows[0]["WorkflowStatus"];
            return oGetWorkflowCls;
        }

        public static string GetButtonProcessNextLinkUrl(string ConnectionString, string Caption, string WorkflowActionId)
        {
            if (string.IsNullOrEmpty(WorkflowActionId)) return "";
            string Query = "select WorkflowDefId,RecordId,ProcessType from TableWorkflowAction where Id='" + WorkflowActionId + "' and [sent]=0 and ProcessDone=0 and EmployeeLoginName=@LoginName and toRole=@RoleId";
            SqlConnection oSqlConnection = new SqlConnection(ConnectionString);
            oSqlConnection.Open();
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@LoginName", SqlDbType.VarChar).Value = WebSessionUtility.GetCurrentLoginUser().LoginName;
            oSqlCommand.Parameters.Add("@RoleId", SqlDbType.VarChar).Value = WebSessionUtility.GetCurrentLoginUser().RoleId;

            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            DataTable dtResult = new DataTable();
            sqlda.Fill(dtResult);
            if (dtResult.Rows.Count == 0) return "";
            string WorkflowDefId = (string)dtResult.Rows[0]["WorkflowDefId"];
            string RecordId = (string)dtResult.Rows[0]["RecordId"];
            string ProcessType = (string)dtResult.Rows[0]["ProcessType"];
            if (ProcessType.Equals("view")) return "";
            string RetHtml = "<input type=button value=\"" + Caption + "\" onclick=\"javascript:ClientProcessNextLink('" + WorkflowDefId + "','" + WorkflowActionId + "','" + RecordId + "');\">";
            return RetHtml;
        }


        public static string GetPlugInRunJavascriptNextLink(string ConnectionString, string WorkflowActionId)
        {
            if (string.IsNullOrEmpty(WorkflowActionId)) return "";
            string Query = "select WorkflowDefId,RecordId,ProcessType from TableWorkflowAction where Id='" + WorkflowActionId + "'";
            SqlConnection oSqlConnection = new SqlConnection(ConnectionString);
            oSqlConnection.Open();
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            DataTable dtResult = new DataTable();
            sqlda.Fill(dtResult);
            if (dtResult.Rows.Count == 0) return "";
            string WorkflowDefId = (string)dtResult.Rows[0]["WorkflowDefId"];
            string RecordId = (string)dtResult.Rows[0]["RecordId"];
            string ProcessType = (string)dtResult.Rows[0]["ProcessType"];
            return "    ClientProcessNextLink('" + WorkflowDefId + "','" + WorkflowActionId + "','" + RecordId + "');";
        }

        public static string GetNextLinkUrl(
            string SiteId,
            string RecordId)
        {
            SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);
            string Query = "select Id,WorkflowDefId from TableWorkflowAction where [sent]=0 and ProcessDone=0 and EmployeeLoginName=@LoginName and toRole=@RoleId and RecordId=@RecordId";
            SqlConnection oSqlConnection = new SqlConnection(oSiteParam.ConnectionString);
            oSqlConnection.Open();
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@LoginName", SqlDbType.VarChar).Value = WebSessionUtility.GetCurrentLoginUser().LoginName;
            oSqlCommand.Parameters.Add("@RoleId", SqlDbType.VarChar).Value = WebSessionUtility.GetCurrentLoginUser().RoleId;
            oSqlCommand.Parameters.Add("@RecordId", SqlDbType.VarChar).Value = RecordId;
            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            DataTable dtResult = new DataTable();
            sqlda.Fill(dtResult);
            if (dtResult.Rows.Count == 0) return null;
            string WorkflowActionId = (string)dtResult.Rows[0]["Id"];
            string WorkflowDefId = (string)dtResult.Rows[0]["WorkflowDefId"];
            string Url = "javascript:ClientProcessNextLink('" + WorkflowDefId + "','" + WorkflowActionId + "','" + RecordId + "');";
            return Url;
            //string Url = Environment.Screen.BuildDialogUrl(SiteId, "WorkflowTaskNextLink", new Environment.ParamCls[]{
            //       new Environment.ParamCls("WorkflowDefId",WorkflowDefId),
            //       new Environment.ParamCls("WorkflowActionId",WorkflowActionId),
            //       new Environment.ParamCls("RecordId",RecordId),
            //});
            //return Url;
        }

        public static string GetTextProcessNextLinkUrl(string ConnectionString, string Caption, string WorkflowActionId)
        {
            string Query = "select WorkflowDefId,RecordId from TableWorkflowAction where Id='" + WorkflowActionId + "'";
            SqlConnection oSqlConnection = new SqlConnection(ConnectionString);
            oSqlConnection.Open();
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            DataTable dtResult = new DataTable();
            sqlda.Fill(dtResult);
            if (dtResult.Rows.Count == 0) return "";
            string WorkflowDefId = (string)dtResult.Rows[0]["WorkflowDefId"];
            string RecordId = (string)dtResult.Rows[0]["RecordId"];
            string RetHtml = "<a href=\"javascript:ClientProcessNextLink('" + WorkflowDefId + "','" + WorkflowActionId + "','" + RecordId + "');\">" + Caption + "</a>";
            return RetHtml;
        }

        public static void UpdateSubjectForWorkflow(SqlTransaction oSqlTransaction, string RecordId, string Subject)
        {
            string Query =
                " Update TableWorkflowAction set Subject=@Subject where RecordId=@RecordId; " +
                //" Update TableWorkflowActionHistory set Subject=@Subject where RecordId=@RecordId; " +
                //" Update TableWorkflowHasReceived set Subject=@Subject where RecordId=@RecordId; " +
                //" Update TableWorkflowHasSent set Subject=@Subject where RecordId=@RecordId; " +
                " Update TableRunningWorkflowTask set Subject=@Subject where ObjectRecordId=@RecordId; ";
            SqlCommand oSqlCommand = oSqlTransaction.Connection.CreateCommand();
            oSqlCommand.Transaction = oSqlTransaction;
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@RecordId", SqlDbType.VarChar).Value = RecordId;
            oSqlCommand.Parameters.Add("@Subject", SqlDbType.NVarChar).Value = Subject;
            oSqlCommand.ExecuteNonQuery();
        }


        public static void DeleteWorkflow(SqlTransaction oSqlTransaction, string RecordId)
        {
            string Query =
                //" Delete from TableWorkflowActionAttachFile where frkWorkflowActionId in (select id from TableWorkflowAction where RecordId=@RecordId);" +
                " Delete from TableWorkflowAction where RecordId=@RecordId;" +
                //" Delete from TableWorkflowActionHistory where RecordId=@RecordId;" +
                //" Delete from TableWorkflowHasSent where RecordId=@RecordId;" +
                //" Delete from TableWorkflowHasReceived where RecordId=@RecordId;" +
                //" Delete from TableWorkflowAttachFile where frkRunningWorkflowTaskId in (select RunningWorkflowTaskId from TableRunningWorkflowTask where ObjectRecordId=@RecordId);" +
                " Delete from TableRunningWorkflowTaskUser where frkRunningWorkflowTaskId in (select RunningWorkflowTaskId from TableRunningWorkflowTask where ObjectRecordId=@RecordId);";
            SqlCommand oSqlCommand = oSqlTransaction.Connection.CreateCommand();
            oSqlCommand.Transaction = oSqlTransaction;
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@RecordId", SqlDbType.VarChar).Value = RecordId;
            oSqlCommand.ExecuteNonQuery();
        }

        public static void DeleteRunningWorkflow(
            SqlTransaction oSqlTransaction,
            string RecordId)
        {
            string Query =
                " Delete from TableRunningWorkflowTaskUser where frkRunningWorkflowTaskId in (select RunningWorkflowTaskId from TableRunningWorkflowTask where ObjectRecordId=@RecordId);" +
                " Delete from TableRunningWorkflowTask where ObjectRecordId=@RecordId; ";
            SqlCommand oSqlCommand = oSqlTransaction.Connection.CreateCommand();
            oSqlCommand.Transaction = oSqlTransaction;
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@RecordId", SqlDbType.VarChar).Value = RecordId;
            oSqlCommand.ExecuteNonQuery();
        }

        public static bool ServerCheckWorkflowUpdatePermission(
            string ConnectionString,
            string SiteId,
            string RecordId,
            string ForUser,
            string Owner)
        {
            //check xem hoan thanh chua
            bool HasFinished = HasFinishAllTask(SiteId, RecordId);
            if (HasFinished) return true;

            SqlConnection oSqlConnection = new SqlConnection(ConnectionString);
            oSqlConnection.Open();

            string Query =
                " select DocumentNextHistoryId from TableDocumentNextHistory where ObjectId=@ObjectId";
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@ObjectId", SqlDbType.VarChar).Value = RecordId;
            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            DataTable dtResult = new DataTable();
            sqlda.Fill(dtResult);
            if (dtResult.Rows.Count == 0)
            {
                if (ForUser.ToLower().Equals(Owner.ToLower()))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }


            Query =
                " select * from TableWorkflowPermissionGrant where Allow=1 and PermissionType='update' and ObjectId=@ObjectId and ltrim(rtrim(ForUser))=@ForUser";
            oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@ObjectId", SqlDbType.VarChar).Value = RecordId;
            oSqlCommand.Parameters.Add("@ForUser", SqlDbType.VarChar).Value = ForUser.Trim();
            sqlda = new SqlDataAdapter(oSqlCommand);
            dtResult = new DataTable();
            sqlda.Fill(dtResult);
            return dtResult.Rows.Count > 0;
        }



        public static bool ServerCheckWorkflowDeletePermission(
            string ConnectionString,
            string SiteId,
            string RecordId,
            string ForUser,
            string Owner)
        {
            bool HasFinished = HasFinishAllTask(SiteId, RecordId);
            if (HasFinished) return true;

            SqlConnection oSqlConnection = new SqlConnection(ConnectionString);
            oSqlConnection.Open();

            string Query =
                " select DocumentNextHistoryId from TableDocumentNextHistory where ObjectId=@ObjectId";
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@ObjectId", SqlDbType.VarChar).Value = RecordId;
            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            DataTable dtResult = new DataTable();
            sqlda.Fill(dtResult);
            if (dtResult.Rows.Count == 0)
            {
                if (ForUser.ToLower().Equals(Owner.ToLower()))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

            Query =
                " select * from TableWorkflowPermissionGrant where Allow=1 and PermissionType='Delete' and ObjectId=@ObjectId and ltrim(rtrim(ForUser))=@ForUser";
            oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@ObjectId", SqlDbType.VarChar).Value = RecordId;
            oSqlCommand.Parameters.Add("@ForUser", SqlDbType.VarChar).Value = ForUser.Trim();
            sqlda = new SqlDataAdapter(oSqlCommand);
            dtResult = new DataTable();
            sqlda.Fill(dtResult);
            return dtResult.Rows.Count > 0;
        }

        public static bool ServerCheckWorkflowReportPermission(
            string ConnectionString,
            string SiteId,
            string RecordId,
            string ForUser,
            string Owner)
        {
            bool HasFinished = HasFinishAllTask(SiteId, RecordId);
            if (HasFinished) return true;

            SqlConnection oSqlConnection = new SqlConnection(ConnectionString);
            oSqlConnection.Open();

            string Query =
                " select DocumentNextHistoryId from TableDocumentNextHistory where ObjectId=@ObjectId";
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@ObjectId", SqlDbType.VarChar).Value = RecordId;
            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            DataTable dtResult = new DataTable();
            sqlda.Fill(dtResult);
            if (dtResult.Rows.Count == 0)
            {
                if (ForUser.ToLower().Equals(Owner.ToLower()))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }

            Query =
                " select * from TableWorkflowPermissionGrant where Allow=1 and PermissionType='Report' and ObjectId=@ObjectId and ltrim(rtrim(ForUser))=@ForUser";
            oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@ObjectId", SqlDbType.VarChar).Value = RecordId;
            oSqlCommand.Parameters.Add("@ForUser", SqlDbType.VarChar).Value = ForUser.Trim();
            sqlda = new SqlDataAdapter(oSqlCommand);
            dtResult = new DataTable();
            sqlda.Fill(dtResult);
            return dtResult.Rows.Count > 0;
        }

        public static string ServerSideGetPlugInJavascriptDoNextLink(string SiteId, string ContentWorkflow, string divMainForm)
        {
            string Javascript =
                AjaxWorkflowTaskNextLink.GetAjaxProNextLinkJavascript(SiteId, ContentWorkflow, divMainForm) +
                " <script language=javascript>\r\n" +
                    "   function ClientViewAttachFileInWorkflow(WorkflowAttachFileId)\r\n" +
                    "   {\r\n" +
                    "       SiteId=document.getElementById(\"txtSiteParam\").value;\r\n" +
                    "       Url=Portal.Workflow.Bussiness.WorkflowBll.ServerSideGetPreviewUrl(SiteId, WorkflowAttachFileId).value;\r\n" +
                    "       window.open(Url,'_blank');\r\n" +
                    "   }\r\n" +

                    "   function ClientGetAttachDocumentIds()\r\n" +
                    "   {\r\n" +
                    "       SelectedIds='';\r\n" +
                    "       Max=0;\r\n" +
                    "       if(document.getElementById(\"txtMaxAttachedDocument\")!=null)\r\n" +
                    "       {\r\n" +
                    "           Max=document.getElementById(\"txtMaxAttachedDocument\").value;\r\n" +
                    "       }\r\n" +
                    "       for(var iIndex=0;iIndex<Max;iIndex++)\r\n" +
                    "       {\r\n" +
                    "           Ids='chk'+iIndex;\r\n" +
                    "           blnChecked=document.getElementById(Ids).checked;\r\n" +
                    "           if(blnChecked)\r\n" +
                    "           {\r\n" +
                    "               Ids='txtIndex'+iIndex;\r\n" +
                    "               Id=document.getElementById(Ids).value;\r\n" +
                    "               SelectedIds=SelectedIds+Id+';';\r\n" +
                    "           }\r\n" +
                    "       }\r\n" +
                    "       return SelectedIds;\r\n" +
                    "   }\r\n" +


                "       function ClientProcessNextLink(WorkflowDefId,WorkflowActionId,RecordId,LinkId)\r\n" +
                "       {\r\n" +
                "           SiteId=document.getElementById(\"txtSiteParam\").value;\r\n" +
                //"           Url=Portal.Workflow.Bussiness.WorkflowBll.ServerSideProcessNextLink(SiteId, WorkflowDefId,WorkflowActionId,RecordId).value;\r\n" +
                //"           if(Url.indexOf('ERROR')!=-1)\r\n" +
                //"           {\r\n" +
                //"               alert(Url);\r\n" +
                //"               return;\r\n" +
                //"           }\r\n" +
                //"           window.open(Url,'_blank');\r\n" +

                "           Html=Portal.Workflow.Bussiness.WorkflowBll.ServerSideProcessAjaxNextLink(SiteId, WorkflowDefId,WorkflowActionId,RecordId,LinkId).value;\r\n" +
                "           if(Html.indexOf('ERROR')!=-1)\r\n" +
                "           {\r\n" +
                "               alert(Html);\r\n" +
                "               return;\r\n" +
                "           }\r\n" +
                "           document.getElementById('content_workflow').innerHTML=Html;\r\n" +
                "       }\r\n" +
                " </script>\r\n";
            return Javascript;
        }

        //[AjaxPro.AjaxMethod]
        //public string ServerSideProcessNextLink(
        //    string SiteId,
        //    string WorkflowDefId,
        //    string WorkflowActionId,
        //    string RecordId)
        //{
        //    try
        //    {
        //        WebSessionUtility.CheckSessionTimeOut(true);
        //        new WorkflowBll().CheckDoNextLinkRunAtServer(SiteId, WorkflowActionId);
        //        string Url = Portal.Environment.Screen.BuildDialogUrl(
        //            SiteId,
        //            "WorkflowTaskNextLink", new Portal.Environment.ParamCls[]{
        //            new Portal.Environment.ParamCls("WorkflowDefId",WorkflowDefId),
        //            new Portal.Environment.ParamCls("WorkflowActionId",WorkflowActionId),
        //            new Portal.Environment.ParamCls("RecordId",RecordId),
        //        });
        //        return Url;
        //    }
        //    catch (Exception ex)
        //    {
        //        return "ERROR: " + ex.Message.ToString();
        //    }
        //}


        [AjaxPro.AjaxMethod]
        public string ServerSideProcessAjaxNextLink(
            string SiteId,
            string WorkflowDefId,
            string WorkflowActionId,
            string RecordId,
            string LinkId)
        {
            try
            {
                WebSessionUtility.CheckSessionTimeOut();
                new WorkflowBll().CheckDoNextLinkRunAtServer(SiteId, WorkflowActionId);
                //string Url = Portal.Environment.Screen.BuildDialogUrl(
                //    SiteId,
                //    "WorkflowTaskNextLink", new Portal.Environment.ParamCls[]{
                //    new Portal.Environment.ParamCls("WorkflowDefId",WorkflowDefId),
                //    new Portal.Environment.ParamCls("WorkflowActionId",WorkflowActionId),
                //    new Portal.Environment.ParamCls("RecordId",RecordId),
                //});
                //return Url;
                string Html = new AjaxWorkflowTaskNextLink().Draw(SiteId, WorkflowDefId, WorkflowActionId, RecordId, LinkId);
                return Html;
            }
            catch (Exception ex)
            {
                return "ERROR: " + ex.Message.ToString();
            }
        }

        public static void FinishTask(SqlTransaction oSqlTransaction, string SiteId, string RecordId)
        {
            bool HasTrans = oSqlTransaction != null;
            if (HasTrans == false)
            {
                SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);
                SqlConnection oSqlConnection = new SqlConnection(oSiteParam.ConnectionString);
                oSqlConnection.Open();
                oSqlTransaction = oSqlConnection.BeginTransaction();
            }
            string CommandText =
                    " Delete from TableWorkflowActionAttachFile where frkWorkflowActionId in (select Id from TableWorkflowAction where RecordId=@RecordId); " +
                    " Delete from TableWorkflowAction where RecordId=@RecordId";
            SqlCommand oSqlCommand = oSqlTransaction.Connection.CreateCommand();
            oSqlCommand.Transaction = oSqlTransaction;
            oSqlCommand.CommandText = CommandText;
            oSqlCommand.Parameters.Add("@RecordId", SqlDbType.VarChar).Value = RecordId;
            try
            {
                oSqlCommand.ExecuteNonQuery();
                DeleteRunningWorkflow(oSqlTransaction, RecordId);
                if (HasTrans == false)
                {
                    oSqlTransaction.Commit();
                }
            }
            catch (Exception ex)
            {
                if (HasTrans == false)
                {
                    oSqlTransaction.Rollback();
                    throw (ex);
                }
            }
        }

        public static bool CheckHasStartWorkflow(
           string SiteId,
           string RecordId)
        {
            SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);

            string Query = "select Id from TableWorkFlowAction where RecordId=@RecordId";
            SqlConnection oSqlConnection = new SqlConnection(oSiteParam.ConnectionString);
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@RecordId", SqlDbType.VarChar).Value = RecordId;
            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            DataTable dtResult = new DataTable();
            sqlda.Fill(dtResult);
            return dtResult.Rows.Count > 0;
        }

        public static bool HasInWorkflowTask(
            string SiteId,
            string RecordId)
        {
            SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);

            string Query = "select Id from TableWorkFlowAction where [sent]=0 and ProcessDone=0 and EmployeeLoginName=@LoginName and toRole=@RoleId and RecordId=@RecordId";
            SqlConnection oSqlConnection = new SqlConnection(oSiteParam.ConnectionString);
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@RecordId", SqlDbType.VarChar).Value = RecordId;
            oSqlCommand.Parameters.Add("@LoginName", SqlDbType.VarChar).Value = WebSessionUtility.GetCurrentLoginUser().LoginName;
            oSqlCommand.Parameters.Add("@RoleId", SqlDbType.VarChar).Value = WebSessionUtility.GetCurrentLoginUser().RoleId;
            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            DataTable dtResult = new DataTable();
            sqlda.Fill(dtResult);
            return dtResult.Rows.Count > 0;
        }


        public static bool HasFinishAllTask(
            string SiteId,
            string RecordId)
        {
            SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);

            string Query = "select Id from TableWorkFlowAction where [sent]=0 and ProcessDone=0 and RecordId=@RecordId";
            Query = "select Id from TableWorkFlowAction where RecordId=@RecordId";
            SqlConnection oSqlConnection = new SqlConnection(oSiteParam.ConnectionString);
            SqlCommand oSqlCommand = oSqlConnection.CreateCommand();
            oSqlCommand.CommandText = Query;
            oSqlCommand.Parameters.Add("@RecordId", SqlDbType.VarChar).Value = RecordId;
            SqlDataAdapter sqlda = new SqlDataAdapter(oSqlCommand);
            DataTable dtResult = new DataTable();
            sqlda.Fill(dtResult);
            return dtResult.Rows.Count == 0;
        }

        public static string GetImageWorkflow(string SiteId, string WorkflowDefId)
        {
            string ImageUrl = "";
            SiteParam oSiteParam = WebEnvironments.CreateSiteParam(SiteId);
            string PngFile = WorkflowDefId + ".png";
            string PicFile = oSiteParam.PathRoot + "\\Images\\Workflows\\" + PngFile;
            if (File.Exists(PicFile))
            {
                ImageUrl = "<div style=\"margin-top:50px;\"><img class=\"CssImageWorkflow\" src=\"" + oSiteParam.HttpRoot + "/Images/Workflows/" + PngFile + "\"></div>";
            }
            return ImageUrl;
        }
    }
}
